From 927bceca6f71d32b9a33459b6d6ee412d4c286e4 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 7 Nov 2024 21:54:37 +0530 Subject: [PATCH 01/51] feat: thunderBroker migration changes with config switch --- core/main/src/broker/broker_utils.rs | 3 +- core/main/src/utils/rpc_utils.rs | 10 - core/sdk/src/api/device/device_operator.rs | 27 + core/sdk/src/utils/rpc_utils.rs | 10 + device/thunder_ripple_sdk/Cargo.toml | 6 +- .../src/bootstrap/boot_thunder.rs | 78 +- .../src/bootstrap/get_config_step.rs | 8 +- .../src/bootstrap/setup_thunder_pool_step.rs | 17 +- .../src/client/plugin_manager.rs | 4 +- .../src/client/thunder_async_client.rs | 306 ++++++++ .../src/client/thunder_client.rs | 266 ++++--- .../src/client/thunder_client2.rs | 157 ++++ .../src/client/thunder_client_pool.rs | 13 +- .../src/client/thunder_plugins_status_mgr.rs | 712 ++++++++++++++++++ device/thunder_ripple_sdk/src/lib.rs | 3 + .../thunder_ripple_sdk/src/thunder_state.rs | 8 +- device/thunder_ripple_sdk/src/utils.rs | 12 +- 17 files changed, 1499 insertions(+), 141 deletions(-) create mode 100644 device/thunder_ripple_sdk/src/client/thunder_async_client.rs create mode 100644 device/thunder_ripple_sdk/src/client/thunder_client2.rs create mode 100644 device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 8d6425a5e..1e863fe89 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -15,7 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use crate::{state::platform_state::PlatformState, utils::rpc_utils::extract_tcp_port}; +use crate::state::platform_state::PlatformState; use futures::stream::{SplitSink, SplitStream}; use futures_util::StreamExt; use jsonrpsee::{core::RpcResult, types::error::CallError}; @@ -24,6 +24,7 @@ use ripple_sdk::{ extn::extn_client_message::ExtnResponse, log::{error, info}, tokio::{self, net::TcpStream}, + utils::rpc_utils::extract_tcp_port, uuid::Uuid, }; use serde_json::Value; diff --git a/core/main/src/utils/rpc_utils.rs b/core/main/src/utils/rpc_utils.rs index 9097a5224..9fc1f5953 100644 --- a/core/main/src/utils/rpc_utils.rs +++ b/core/main/src/utils/rpc_utils.rs @@ -109,13 +109,3 @@ pub fn get_base_method(method: &str) -> String { let method_vec: Vec<&str> = method.split('.').collect(); method_vec.first().unwrap().to_string().to_lowercase() } - -pub fn extract_tcp_port(url: &str) -> String { - let url_split: Vec<&str> = url.split("://").collect(); - if let Some(domain) = url_split.get(1) { - let domain_split: Vec<&str> = domain.split('/').collect(); - domain_split.first().unwrap().to_string() - } else { - url.to_owned() - } -} diff --git a/core/sdk/src/api/device/device_operator.rs b/core/sdk/src/api/device/device_operator.rs index 05ac2ba02..13d9c3f6f 100644 --- a/core/sdk/src/api/device/device_operator.rs +++ b/core/sdk/src/api/device/device_operator.rs @@ -44,6 +44,33 @@ pub enum DeviceChannelRequest { Unsubscribe(DeviceUnsubscribeRequest), } +impl DeviceChannelRequest { + pub fn get_callsign_method(&self) -> (String, String) { + match self { + DeviceChannelRequest::Call(c) => { + let mut collection: Vec<&str> = c.method.split('.').collect(); + let method = collection.pop().unwrap_or_default(); + let callsign = collection.join("."); + (callsign, method.into()) + } + DeviceChannelRequest::Subscribe(s) => (s.module.clone(), s.event_name.clone()), + DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), + } + } + + pub fn is_subscription(&self) -> bool { + !matches!(self, DeviceChannelRequest::Call(_)) + } + + pub fn is_unsubscribe(&self) -> Option { + if let DeviceChannelRequest::Unsubscribe(u) = self { + Some(u.clone()) + } else { + None + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeviceCallRequest { pub method: String, diff --git a/core/sdk/src/utils/rpc_utils.rs b/core/sdk/src/utils/rpc_utils.rs index c77ea07a9..9d2d79bb4 100644 --- a/core/sdk/src/utils/rpc_utils.rs +++ b/core/sdk/src/utils/rpc_utils.rs @@ -20,3 +20,13 @@ use jsonrpsee::core::Error; pub fn rpc_err(msg: impl Into) -> Error { Error::Custom(msg.into()) } + +pub fn extract_tcp_port(url: &str) -> String { + let url_split: Vec<&str> = url.split("://").collect(); + if let Some(domain) = url_split.get(1) { + let domain_split: Vec<&str> = domain.split('/').collect(); + domain_split.first().unwrap().to_string() + } else { + url.to_owned() + } +} diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index 9fc186ca6..ee11bd794 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -44,6 +44,9 @@ regex.workspace = true jsonrpsee = { workspace = true, features = ["macros", "ws-client"] } serde.workspace = true url.workspace = true +serde_json.workspace = true +futures-channel.workspace = true +futures.workspace = true strum = { version = "0.24", default-features = false } strum_macros = "0.24" @@ -56,8 +59,9 @@ csv = "1.1" # Allowing minor updates 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 } +tokio-tungstenite = { workspace = true, features = ["handshake"] } +futures-util = { version = "0.3.28", features = ["sink", "std"], default-features = false} [dev-dependencies] -tokio-tungstenite = { workspace = true, features = ["native-tls"] } ripple_sdk = { path = "../../core/sdk", features = ["tdk"] } diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 61ba1de8b..07e01274c 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -25,21 +25,81 @@ use ripple_sdk::{ }; use super::{get_config_step::ThunderGetConfigStep, setup_thunder_pool_step::ThunderPoolStep}; +use crate::client::thunder_client::ThunderClientBuilder; +use crate::thunder_state::ThunderBootstrapStateWithConfig; +use crate::thunder_state::ThunderState; + +// pub async fn boot_thunder( +// ext_client: ExtnClient, +// plugin_param: ThunderPluginBootParam, +// ) -> Option { +// info!("Booting thunder"); +// if ext_client.get_bool_config("use_with_thunder_broker") { +// info!("Using thunder broker"); + +// if let Ok(thndr_client) = ThunderClientBuilder::get_client(None, None, None, None, None, true) +// .await{ +// let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); +// } + +// None +// } else { +// if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { +// if let Ok(state) = ThunderPoolStep::setup(state).await { +// SetupThunderProcessor::setup(state.clone()).await; +// return Some(state); +// } else { +// error!("Unable to connect to Thunder, error in ThunderPoolStep"); +// } +// } else { +// error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); +// } +// None +// } +// } + +use std::sync::Arc; pub async fn boot_thunder( - state: ExtnClient, + ext_client: ExtnClient, plugin_param: ThunderPluginBootParam, ) -> Option { info!("Booting thunder"); - if let Ok(state) = ThunderGetConfigStep::setup(state, plugin_param).await { - if let Ok(state) = ThunderPoolStep::setup(state).await { - SetupThunderProcessor::setup(state.clone()).await; - return Some(state); - } else { - error!("Unable to connect to Thunder, error in ThunderPoolStep"); + if ext_client.get_bool_config("use_with_thunder_broker") { + info!("Using thunder broker"); + + if let Ok(thndr_client) = + ThunderClientBuilder::get_client(None, None, None, None, None, true).await + { + let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); + + let thndr_boot_statecfg = ThunderBootstrapStateWithConfig { + extn_client: ext_client, + url: None, + pool_size: None, + plugin_param: None, + thunder_connection_state: None, + }; + + let thndr_boot_stateclient = ThunderBootstrapStateWithClient { + prev: thndr_boot_statecfg, + state: thunder_state, + }; + return Some(thndr_boot_stateclient); } + + None } else { - error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); + if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { + if let Ok(state) = ThunderPoolStep::setup(state).await { + SetupThunderProcessor::setup(state.clone()).await; + return Some(state); + } else { + error!("Unable to connect to Thunder, error in ThunderPoolStep"); + } + } else { + error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); + } + None } - None } diff --git a/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs b/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs index 77e477fb9..4a940333c 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs @@ -92,10 +92,10 @@ impl ThunderGetConfigStep { } return Ok(ThunderBootstrapStateWithConfig { extn_client: state, - url: gateway_url, - pool_size, - plugin_param: expected_plugins, - thunder_connection_state: Arc::new(ThunderConnectionState::new()), + url: Some(gateway_url), + pool_size: Some(pool_size), + plugin_param: Some(expected_plugins), + thunder_connection_state: Some(Arc::new(ThunderConnectionState::new())), }); } } diff --git a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs index 252b2971a..b2bd0c743 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs @@ -43,13 +43,18 @@ impl ThunderPoolStep { let pool_size = state.pool_size; let url = state.url.clone(); let thunder_connection_state = state.thunder_connection_state.clone(); - if pool_size < 2 { + if pool_size < Some(2) { warn!("Pool size of 1 is not recommended, there will be no dedicated connection for Controller events"); return Err(RippleError::BootstrapError); } let controller_pool = ripple_sdk::tokio::time::timeout( Duration::from_secs(10), - ThunderClientPool::start(url.clone(), None, thunder_connection_state.clone(), 1), + ThunderClientPool::start( + url.clone().unwrap(), + None, + thunder_connection_state.clone(), + 1, + ), ) .await; @@ -71,7 +76,7 @@ impl ThunderPoolStep { let expected_plugins = state.plugin_param.clone(); let tc = Box::new(controller_pool); let (plugin_manager_tx, failed_plugins) = - PluginManager::start(tc, expected_plugins.clone()).await; + PluginManager::start(tc, expected_plugins.clone().unwrap()).await; if !failed_plugins.is_empty() { error!( @@ -80,7 +85,7 @@ impl ThunderPoolStep { ); loop { let failed_plugins = PluginManager::activate_mandatory_plugins( - expected_plugins.clone(), + expected_plugins.unwrap(), plugin_manager_tx.clone(), ) .await; @@ -98,10 +103,10 @@ impl ThunderPoolStep { } let client = ThunderClientPool::start( - url, + url.clone().unwrap(), Some(plugin_manager_tx), thunder_connection_state.clone(), - pool_size - 1, + pool_size - Some(1), ) .await; diff --git a/device/thunder_ripple_sdk/src/client/plugin_manager.rs b/device/thunder_ripple_sdk/src/client/plugin_manager.rs index cd25b823b..0e46d4a76 100644 --- a/device/thunder_ripple_sdk/src/client/plugin_manager.rs +++ b/device/thunder_ripple_sdk/src/client/plugin_manager.rs @@ -496,7 +496,7 @@ mod tests { let controller_pool = ThunderClientPool::start( url.clone(), None, - Arc::new(ThunderConnectionState::new()), + Some(Arc::new(ThunderConnectionState::new())), 1, ) .await; @@ -519,7 +519,7 @@ mod tests { let client = ThunderClientPool::start( url, Some(plugin_manager_tx_clone), - Arc::new(ThunderConnectionState::new()), + Some(Arc::new(ThunderConnectionState::new())), 4, ) .await; diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs new file mode 100644 index 000000000..563d0df24 --- /dev/null +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -0,0 +1,306 @@ +// 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::time::Duration; + +use futures::stream::{SplitSink, SplitStream}; +use futures_util::{SinkExt, StreamExt}; +use ripple_sdk::{ + api::{ + device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, + }, + log::{debug, error, info}, + tokio::{ + self, + net::TcpStream, + sync::mpsc::{Receiver, Sender}, + }, + utils::{error::RippleError, rpc_utils::extract_tcp_port}, +}; + +use serde_json::json; +use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; + +use crate::utils::get_next_id; + +use super::thunder_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; + +#[derive(Clone, Debug)] +pub struct ThunderAsyncClient { + status_manager: StatusManager, + sender: BrokerSender, + callback: BrokerCallback, +} + +#[derive(Clone, Debug)] +pub struct ThunderAsyncRequest { + pub id: u64, + request: DeviceChannelRequest, +} + +impl ThunderAsyncRequest { + pub fn new(request: DeviceChannelRequest) -> Self { + Self { + id: get_next_id(), + request, + } + } +} + +#[derive(Clone, Debug)] +pub struct ThunderAsyncResponse { + pub id: Option, + pub result: Result, +} + +impl ThunderAsyncResponse { + fn new_response(response: JsonRpcApiResponse) -> Self { + Self { + id: None, + result: Ok(response), + } + } + + fn new_error(id: u64, e: RippleError) -> Self { + Self { + id: Some(id), + result: Err(e), + } + } +} + +impl ThunderAsyncClient { + pub fn get_sender(&self) -> BrokerSender { + self.sender.clone() + } + + async fn create_ws( + endpoint: &str, + ) -> ( + SplitSink, Message>, + SplitStream>, + ) { + info!("Broker Endpoint url {}", endpoint); + + let url = url::Url::parse(endpoint).unwrap(); + let port = extract_tcp_port(endpoint); + info!("Url host str {}", url.host_str().unwrap()); + let mut index = 0; + + loop { + // Try connecting to the tcp port first + if let Ok(v) = TcpStream::connect(&port).await { + // Setup handshake for websocket with the tcp port + // Some WS servers lock on to the Port but not setup handshake till they are fully setup + if let Ok((stream, _)) = client_async(endpoint, v).await { + break stream.split(); + } + } + if (index % 10).eq(&0) { + error!( + "Broker with {} failed with retry for last {} secs in {}", + endpoint, index, port + ); + } + index += 1; + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + + fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result, RippleError> { + let mut requests = Vec::new(); + let id = request.id; + let (callsign, method) = request.request.get_callsign_method(); + if method.is_empty() { + return Err(RippleError::InvalidInput); + } + // check if the plugin is activated. + let status = match self.status_manager.get_status(callsign.clone()) { + Some(v) => v.clone(), + None => { + self.status_manager + .add_broker_request_to_pending_list(callsign.clone(), request.clone()); + // PluginState is not available with StateManager, create an internal thunder request to activate the plugin + let request = self + .status_manager + .generate_plugin_status_request(callsign.clone()); + requests.push(request.to_string()); + return Ok(requests); + } + }; + + if status.state.is_missing() { + error!("Plugin {} is missing", callsign); + return Err(RippleError::ServiceError); + } + + if status.state.is_activating() { + info!("Plugin {} is activating", callsign); + return Err(RippleError::ServiceNotReady); + } + + if !status.state.is_activated() { + // add the broker request to pending list + self.status_manager + .add_broker_request_to_pending_list(callsign.clone(), request.clone()); + // create an internal thunder request to activate the plugin + let request = self + .status_manager + .generate_plugin_activation_request(callsign.clone()); + requests.push(request.to_string()); + return Ok(requests); + } + + match &request.request { + DeviceChannelRequest::Call(c) => { + // Simple request and response handling + requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": c.method, + "params": c.params + }) + .to_string(), + ) + } + DeviceChannelRequest::Unsubscribe(_) => requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.unregister", callsign), + "params": { + "event": method, + "id": "client.events" + } + }) + .to_string(), + ), + DeviceChannelRequest::Subscribe(_) => requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.register", callsign), + "params": json!({ + "event": method, + "id": "client.events" + }) + }) + .to_string(), + ), + } + + Ok(requests) + } + + pub fn new(callback: BrokerCallback, tx: Sender) -> Self { + Self { + status_manager: StatusManager::new(), + sender: BrokerSender { sender: tx.clone() }, + callback, + } + } + + pub async fn start( + &self, + url: &str, + mut tr: Receiver, + ) -> Receiver { + let callback = self.callback.clone(); + let (mut ws_tx, mut ws_rx) = Self::create_ws(url).await; + // send the first request to the broker. This is the controller statechange subscription request + let status_request = self + .status_manager + .generate_state_change_subscribe_request(); + + let _feed = ws_tx + .feed(tokio_tungstenite::tungstenite::Message::Text( + status_request.to_string(), + )) + .await; + let _flush = ws_tx.flush().await; + let client_c = self.clone(); + let callback_for_sender = callback.clone(); + tokio::pin! { + let read = ws_rx.next(); + } + loop { + tokio::select! { + Some(value) = &mut read => { + match value { + Ok(v) => { + if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { + client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; + } + else { + // send the incoming text without context back to the sender + Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + } + } + }, + Err(e) => { + error!("Broker Websocket error on read {:?}", e); + // Time to reconnect Thunder with existing subscription + break; + } + } + }, + Some(request) = tr.recv() => { + debug!("Got request from receiver for broker {:?}", request); + match client_c.prepare_request(&request) { + Ok(updated_request) => { + debug!("Sending request to broker {:?}", updated_request); + for r in updated_request { + let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + let _flush = ws_tx.flush().await; + } + } + Err(e) => { + let response = ThunderAsyncResponse::new_error(request.id,e.clone()); + match e { + RippleError::ServiceNotReady => { + info!("Thunder Service not ready, request is now in pending list {:?}", request); + }, + _ => { + error!("error preparing request {:?}", e) + } + } + callback_for_sender.send(response).await + } + } + } + } + } + // when WS is disconnected return the tr back to caller helps restabilish connection + tr + } + + /// Default handler method for the broker to remove the context and send it back to the + /// client for consumption + async fn handle_jsonrpc_response(result: &[u8], callback: BrokerCallback) { + if let Ok(message) = serde_json::from_slice::(result) { + callback + .send(ThunderAsyncResponse::new_response(message)) + .await + } else { + error!("Invalid JSON RPC message sent by Thunder"); + } + } + + pub async fn send(&self, request: ThunderAsyncRequest) {} +} diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 99b1036d4..28df6980d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -56,13 +56,42 @@ use url::Url; use crate::thunder_state::ThunderConnectionState; use crate::utils::get_error_value; +use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; use super::thunder_client_pool::ThunderPoolCommand; +use super::thunder_plugins_status_mgr::BrokerCallback; use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; +use ripple_sdk::tokio::sync::mpsc::Receiver; use std::{env, process::Command}; +#[derive(Debug)] +pub struct ThunderClientManager; + +impl ThunderClientManager { + fn manage( + client: ThunderClient, + mut request_tr: Receiver, + mut response_tr: Receiver, + ) { + let client_c = client.clone(); + tokio::spawn(async move { + loop { + if let Some(thndr_asynclient) = &client_c.thndr_asynclient { + request_tr = thndr_asynclient.start("", request_tr).await; + } + error!("Thunder disconnected so reconnecting") + } + }); + + tokio::spawn(async move { + while let Some(v) = response_tr.recv().await { + // check with thunder client callbacks and subscriptions + } + }); + } +} pub struct ThunderClientBuilder; #[derive(Debug)] @@ -161,9 +190,10 @@ impl ThunderMessage { pub struct ThunderClient { pub sender: Option>, pub pooled_sender: Option>, - pub id: Uuid, + pub id: Option, pub plugin_manager_tx: Option>, pub subscriptions: Option>>>, + pub thndr_asynclient: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -542,120 +572,159 @@ impl ThunderClientBuilder { } pub async fn get_client( - url: Url, + url: Option, plugin_manager_tx: Option>, pool_tx: Option>, - thunder_connection_state: Arc, + thunder_connection_state: Option>, existing_client: Option, + use_thndbroker: bool, ) -> Result { - let id = Uuid::new_v4(); - - info!("initiating thunder connection {}", url); - let subscriptions = Arc::new(Mutex::new(HashMap::::default())); - let (s, mut r) = mpsc::channel::(32); - let pmtx_c = plugin_manager_tx.clone(); - let client = Self::create_client(url, thunder_connection_state.clone()).await; - // add error handling here - if client.is_err() { - error!("Unable to connect to thunder: {client:?}"); - return Err(RippleError::BootstrapError); - } + if !use_thndbroker { + let id = Uuid::new_v4(); - let client = client.unwrap(); - let subscriptions_c = subscriptions.clone(); - tokio::spawn(async move { - while let Some(message) = r.recv().await { - if !client.is_connected() { - if let Some(ptx) = pool_tx { - warn!( - "Client {} became disconnected, removing from pool message {:?}", - id, message - ); - // Remove the client and then try the message again with a new client - let pool_msg = ThunderPoolCommand::ResetThunderClient(id); - mpsc_send_and_log(&ptx, pool_msg, "ResetThunderClient").await; - let pool_msg = ThunderPoolCommand::ThunderMessage(message); - mpsc_send_and_log(&ptx, pool_msg, "RetryThunderMessage").await; - return; - } + if let Some(url) = url { + info!("initiating thunder connection {}", url); + } else { + error!("URL is None, cannot initiate thunder connection"); + return Err(RippleError::BootstrapError); + } + let subscriptions = + Arc::new(Mutex::new(HashMap::::default())); + let (s, mut r) = mpsc::channel::(32); + let pmtx_c = plugin_manager_tx.clone(); + let client = match url { + Some(ref url) => { + Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()) + .await } - info!("Client {} sending thunder message {:?}", id, message); - match message { - ThunderMessage::ThunderCallMessage(thunder_message) => { - ThunderClient::call(&client, thunder_message, plugin_manager_tx.clone()) - .await; - } - ThunderMessage::ThunderSubscribeMessage(thunder_message) => { - ThunderClient::subscribe( - id, - &client, - &subscriptions_c, - thunder_message, - plugin_manager_tx.clone(), - pool_tx.clone(), - ) - .await; - } - ThunderMessage::ThunderUnsubscribeMessage(thunder_message) => { - ThunderClient::unsubscribe(&client, &subscriptions_c, thunder_message) - .await; - } + None => { + error!("URL is None, cannot initiate thunder connection"); + return Err(RippleError::BootstrapError); } + }; + // add error handling here + if client.is_err() { + error!("Unable to connect to thunder: {client:?}"); + return Err(RippleError::BootstrapError); } - }); - if let Some(old_client) = existing_client { - // Re-subscribe for each subscription that was active on the old client - if let Some(subscriptions) = old_client.subscriptions { - // Reactivate the plugin state - let (plugin_rdy_tx, plugin_rdy_rx) = oneshot::channel::(); - if let Some(tx) = pmtx_c.clone() { - let msg = PluginManagerCommand::ReactivatePluginState { tx: plugin_rdy_tx }; - mpsc_send_and_log(&tx, msg, "ResetPluginState").await; - if let Ok(res) = plugin_rdy_rx.await { - res.ready().await; + let client = client.unwrap(); + let subscriptions_c = subscriptions.clone(); + tokio::spawn(async move { + while let Some(message) = r.recv().await { + if !client.is_connected() { + if let Some(ptx) = pool_tx { + warn!( + "Client {} became disconnected, removing from pool message {:?}", + id, message + ); + // Remove the client and then try the message again with a new client + let pool_msg = ThunderPoolCommand::ResetThunderClient(id); + mpsc_send_and_log(&ptx, pool_msg, "ResetThunderClient").await; + let pool_msg = ThunderPoolCommand::ThunderMessage(message); + mpsc_send_and_log(&ptx, pool_msg, "RetryThunderMessage").await; + return; + } } - } - let mut subs = subscriptions.lock().await; - for (subscribe_method, tsub) in subs.iter_mut() { - let mut listeners = - HashMap::>::default(); - std::mem::swap(&mut listeners, &mut tsub.listeners); - for (sub_id, listener) in listeners { - let thunder_message: ThunderSubscribeMessage = { - Self::parse_subscribe_method(subscribe_method) - .map(|(module, event_name)| ThunderSubscribeMessage { - module, - event_name, - params: tsub.params.clone(), - handler: listener, - callback: None, - sub_id: Some(sub_id), - }) - .unwrap() - }; - let resp = s - .send(ThunderMessage::ThunderSubscribeMessage(thunder_message)) + info!("Client {} sending thunder message {:?}", id, message); + match message { + ThunderMessage::ThunderCallMessage(thunder_message) => { + ThunderClient::call( + &client, + thunder_message, + plugin_manager_tx.clone(), + ) + .await; + } + ThunderMessage::ThunderSubscribeMessage(thunder_message) => { + ThunderClient::subscribe( + id, + &client, + &subscriptions_c, + thunder_message, + plugin_manager_tx.clone(), + pool_tx.clone(), + ) .await; - if resp.is_err() { - if let Some((module, _)) = + } + ThunderMessage::ThunderUnsubscribeMessage(thunder_message) => { + ThunderClient::unsubscribe(&client, &subscriptions_c, thunder_message) + .await; + } + } + } + }); + + if let Some(old_client) = existing_client { + // Re-subscribe for each subscription that was active on the old client + if let Some(subscriptions) = old_client.subscriptions { + // Reactivate the plugin state + let (plugin_rdy_tx, plugin_rdy_rx) = + oneshot::channel::(); + if let Some(tx) = pmtx_c.clone() { + let msg = PluginManagerCommand::ReactivatePluginState { tx: plugin_rdy_tx }; + mpsc_send_and_log(&tx, msg, "ResetPluginState").await; + if let Ok(res) = plugin_rdy_rx.await { + res.ready().await; + } + } + let mut subs = subscriptions.lock().await; + for (subscribe_method, tsub) in subs.iter_mut() { + let mut listeners = + HashMap::>::default(); + std::mem::swap(&mut listeners, &mut tsub.listeners); + for (sub_id, listener) in listeners { + let thunder_message: ThunderSubscribeMessage = { Self::parse_subscribe_method(subscribe_method) - { - error!("Failed to send re-subscribe message for {}", module); + .map(|(module, event_name)| ThunderSubscribeMessage { + module, + event_name, + params: tsub.params.clone(), + handler: listener, + callback: None, + sub_id: Some(sub_id), + }) + .unwrap() + }; + let resp = s + .send(ThunderMessage::ThunderSubscribeMessage(thunder_message)) + .await; + if resp.is_err() { + if let Some((module, _)) = + Self::parse_subscribe_method(subscribe_method) + { + error!("Failed to send re-subscribe message for {}", module); + } } } } } } - } - Ok(ThunderClient { - sender: Some(s), - pooled_sender: None, - id, - plugin_manager_tx: pmtx_c, - subscriptions: Some(subscriptions), - }) + Ok(ThunderClient { + sender: Some(s), + pooled_sender: None, + id: Some(id), + plugin_manager_tx: pmtx_c, + subscriptions: Some(subscriptions), + thndr_asynclient: None, + }) + } else { + let (sender, tr) = mpsc::channel(10); + let callback = BrokerCallback { sender }; + let (broker_tx, broker_rx) = mpsc::channel(10); + let client = ThunderAsyncClient::new(callback, broker_tx); + let thunder_client = ThunderClient { + sender: None, + pooled_sender: None, + id: None, + plugin_manager_tx: None, + subscriptions: None, + thndr_asynclient: Some(client), // client, + }; + ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); + Ok(thunder_client) + } } #[cfg(test)] @@ -663,9 +732,10 @@ impl ThunderClientBuilder { ThunderClient { sender: Some(sender), pooled_sender: None, - id: Uuid::new_v4(), + id: Some(Uuid::new_v4()), plugin_manager_tx: None, subscriptions: None, + thndr_asynclient: None, } } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client2.rs b/device/thunder_ripple_sdk/src/client/thunder_client2.rs new file mode 100644 index 000000000..04babdea9 --- /dev/null +++ b/device/thunder_ripple_sdk/src/client/thunder_client2.rs @@ -0,0 +1,157 @@ +// 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; +use ripple_sdk::api::device::device_operator::DeviceChannelRequest; +use ripple_sdk::api::device::device_operator::DeviceOperator; +use ripple_sdk::log::error; +use ripple_sdk::tokio::sync::mpsc::Receiver; + +use ripple_sdk::{ + api::device::device_operator::DeviceResponseMessage, + tokio::sync::mpsc::{self, Sender as MpscSender}, +}; + +use ripple_sdk::{ + api::device::device_operator::{ + DeviceCallRequest, DeviceSubscribeRequest, DeviceUnsubscribeRequest, + }, + serde_json::Value, + tokio, +}; + +use ripple_sdk::{ + tokio::sync::oneshot::{self, Sender as OneShotSender}, + utils::error::RippleError, +}; + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; + +use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; +use super::thunder_plugins_status_mgr::BrokerCallback; + +pub struct ThunderClientBuilder; + +pub type BrokerSubMap = HashMap>>; + +#[derive(Debug, Clone)] +pub struct ThunderClient { + client: ThunderAsyncClient, + subscriptions: Arc>, + callbacks: Arc>>>>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct DefaultThunderResult { + pub success: bool, +} + +impl ThunderClient { + fn add_to_callback(&self, request: &ThunderAsyncRequest) {} + + // if already subscibed updated handlers + fn check_sub(&self, request: &DeviceSubscribeRequest) -> Option { + None + } + + // if only one handler cleanup + fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { + None + } +} + +#[async_trait] +impl DeviceOperator for ThunderClient { + async fn call(&self, request: DeviceCallRequest) -> DeviceResponseMessage { + let (tx, rx) = oneshot::channel::(); + let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); + self.add_to_callback(&async_request); + self.client.send(async_request).await; + match rx.await { + Ok(response) => response, + Err(_) => DeviceResponseMessage { + message: Value::Null, + sub_id: None, + }, + } + } + + async fn subscribe( + &self, + request: DeviceSubscribeRequest, + handler: mpsc::Sender, + ) -> DeviceResponseMessage { + if let Some(subscribe_request) = self.check_sub(&request) { + let (tx, rx) = oneshot::channel::(); + self.add_to_callback(&subscribe_request); + self.client.send(subscribe_request).await; + rx.await.unwrap() + } else { + DeviceResponseMessage { + message: Value::Null, + sub_id: None, + } + } + } + + async fn unsubscribe(&self, request: DeviceUnsubscribeRequest) { + // deprecate + } +} + +#[derive(Debug)] +pub struct ThunderClientManager; + +impl ThunderClientManager { + fn manage( + client: ThunderClient, + mut request_tr: Receiver, + mut response_tr: Receiver, + ) { + let client_c = client.clone(); + tokio::spawn(async move { + loop { + request_tr = client_c.client.start("", request_tr).await; + error!("Thunder disconnected so reconnecting") + } + }); + + tokio::spawn(async move { + while let Some(v) = response_tr.recv().await { + // check with thunder client callbacks and subscriptions + } + }); + } +} + +impl ThunderClientBuilder { + pub async fn get_client() -> Result { + let (sender, tr) = mpsc::channel(10); + let callback = BrokerCallback { sender }; + let (broker_tx, broker_rx) = mpsc::channel(10); + let client = ThunderAsyncClient::new(callback, broker_tx); + let thunder_client = ThunderClient { + client, + subscriptions: Arc::new(RwLock::new(HashMap::new())), + callbacks: Arc::new(RwLock::new(HashMap::new())), + }; + ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); + Ok(thunder_client) + } +} diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 1f7c4ff15..fca9b6da8 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -57,7 +57,7 @@ impl ThunderClientPool { pub async fn start( url: Url, plugin_manager_tx: Option>, - thunder_connection_state: Arc, + thunder_connection_state: Option>, size: u32, ) -> Result { debug!("Starting a Thunder connection pool of size {}", size); @@ -66,11 +66,12 @@ impl ThunderClientPool { let mut clients = Vec::default(); for _ in 0..size { let client = ThunderClientBuilder::get_client( - url.clone(), + Some(url.clone()), plugin_manager_tx.clone(), Some(s.clone()), thunder_connection_state.clone(), None, + false, ) .await; if let Ok(c) = client { @@ -128,14 +129,15 @@ impl ThunderClientPool { ThunderPoolCommand::ResetThunderClient(client_id) => { // Remove the given client and then start a new one to replace it let mut itr = pool.clients.iter(); - let i = itr.position(|x| x.client.id == client_id); + let i = itr.position(|x| x.client.id == Some(client_id)); if let Some(index) = i { let client = ThunderClientBuilder::get_client( - url.clone(), + Some(url.clone()), plugin_manager_tx.clone(), Some(sender_for_thread.clone()), thunder_connection_state.clone(), pool.clients.get(index).map(|x| x.client.clone()), + false, ) .await; if let Ok(client) = client { @@ -156,9 +158,10 @@ impl ThunderClientPool { Ok(ThunderClient { sender: None, pooled_sender: Some(s), - id: Uuid::new_v4(), + id: Some(Uuid::new_v4()), plugin_manager_tx: pmtx_c, subscriptions: None, + thndr_asynclient: None, }) } diff --git a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs new file mode 100644 index 000000000..8a2e2b486 --- /dev/null +++ b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs @@ -0,0 +1,712 @@ +// 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, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, RwLock, + }, +}; + +use ripple_sdk::{ + api::gateway::rpc_gateway_api::JsonRpcApiResponse, + chrono::{DateTime, Duration, Utc}, + framework::RippleResponse, + log::{error, info, warn}, + tokio::sync::mpsc::Sender, + utils::error::RippleError, +}; +use serde::{Deserialize, Serialize}; +use serde_json::json; + +use crate::utils::get_next_id; + +use super::thunder_async_client::{ThunderAsyncRequest, ThunderAsyncResponse}; + +#[derive(Clone, Debug)] +pub struct BrokerSender { + pub sender: Sender, +} + +impl BrokerSender { + // Method to send the request to the underlying broker for handling. + pub async fn send(&self, request: ThunderAsyncRequest) -> RippleResponse { + if let Err(e) = self.sender.send(request).await { + error!("Error sending to broker {:?}", e); + Err(RippleError::SendFailure) + } else { + Ok(()) + } + } +} + +/// BrokerCallback will be used by the communication broker to send the firebolt response +/// back to the gateway for client consumption +#[derive(Clone, Debug)] +pub struct BrokerCallback { + pub sender: Sender, +} + +impl BrokerCallback { + pub async fn send(&self, response: ThunderAsyncResponse) { + if let Err(_) = self.sender.send(response).await { + error!("error returning callback for request") + } + } +} + +// defautl timeout for plugin activation in seconds +const DEFAULT_PLUGIN_ACTIVATION_TIMEOUT: i64 = 8; + +// As per thunder 4_4 documentation, the statechange event is published under the method "client.events.1.statechange" +// But it didn't work, most probably a documentation issue. +// const STATE_CHANGE_EVENT_METHOD: &str = "client.events.1.statechange"; + +const STATE_CHANGE_EVENT_METHOD: &str = "thunder.Broker.Controller.events.statechange"; + +#[derive(Debug, Deserialize, PartialEq, Serialize, Clone)] +pub struct Status { + pub callsign: String, + pub state: String, +} + +#[derive(Debug, Deserialize)] +pub struct ThunderError { + pub code: i32, + pub message: String, +} + +impl ThunderError { + pub fn get_state(&self) -> State { + match self.message.as_str() { + "ERROR_INPROGRESS" | "ERROR_PENDING_CONDITIONS" => State::InProgress, + "ERROR_UNKNOWN_KEY" => State::Missing, + _ => State::Unknown, + } + } +} + +impl Status { + pub fn to_state(&self) -> State { + match self.state.as_str() { + "activated" | "resumed" | "suspended" => State::Activated, + "deactivated" => State::Deactivated, + "deactivation" => State::Deactivation, + "activation" | "precondition" => State::Activation, + _ => State::Unavailable, + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct StateChangeEvent { + pub callsign: String, + pub state: State, +} + +#[derive(Debug, Deserialize, PartialEq, Serialize, Clone)] +pub enum State { + Activated, + Activation, + Deactivated, + Deactivation, + Unavailable, + Precondition, + Suspended, + Resumed, + Missing, + Error, + InProgress, + Unknown, +} + +impl State { + pub fn is_activated(&self) -> bool { + matches!(self, State::Activated) + } + pub fn is_activating(&self) -> bool { + matches!(self, State::Activation) + } + pub fn is_missing(&self) -> bool { + matches!(self, State::Missing) + } + pub fn is_unavailable(&self) -> bool { + matches!(self, State::Unavailable | State::Unknown | State::Missing) + } +} + +#[derive(Debug, Clone)] +pub struct ThunderPluginState { + pub state: State, + pub activation_timestamp: DateTime, + pub pending_requests: Vec, +} +#[derive(Debug, Clone)] +pub struct StatusManager { + pub status: Arc>>, + pub inprogress_plugins_request: Arc>>, +} + +impl Default for StatusManager { + fn default() -> Self { + Self::new() + } +} + +impl StatusManager { + pub fn new() -> Self { + Self { + status: Arc::new(RwLock::new(HashMap::new())), + inprogress_plugins_request: Arc::new(RwLock::new(HashMap::new())), + } + } + + fn get_controller_call_sign() -> String { + "Controller.1.".to_string() + } + + pub fn update_status(&self, plugin_name: String, state: State) { + info!( + "Updating the status of the plugin: {:?} to state: {:?}", + plugin_name, state + ); + let mut status = self.status.write().unwrap(); + // get the current plugin state from hashmap and update the State + if let Some(plugin_state) = status.get_mut(&plugin_name) { + plugin_state.state = state; + } else { + // if the plugin is not present in the hashmap, add it + status.insert( + plugin_name, + ThunderPluginState { + state, + activation_timestamp: Utc::now(), + pending_requests: Vec::new(), + }, + ); + } + } + + pub fn add_broker_request_to_pending_list( + &self, + plugin_name: String, + request: ThunderAsyncRequest, + ) { + let mut status = self.status.write().unwrap(); + if let Some(plugin_state) = status.get_mut(&plugin_name) { + plugin_state.pending_requests.push(request); + } else { + status.insert( + plugin_name.clone(), + ThunderPluginState { + state: State::Unknown, + activation_timestamp: Utc::now(), + pending_requests: vec![request], + }, + ); + } + // update the time stamp + if let Some(plugin_state) = status.get_mut(&plugin_name) { + plugin_state.activation_timestamp = Utc::now(); + } + } + + // clear all pending requests for the given plugin and return the list of requests to the caller + // Also return a flag to indicate if activation time has expired. + pub fn retrive_pending_broker_requests( + &self, + plugin_name: String, + ) -> (Vec, bool) { + let mut status = self.status.write().unwrap(); + if let Some(plugin_state) = status.get_mut(&plugin_name) { + let pending_requests = plugin_state.pending_requests.clone(); + plugin_state.pending_requests.clear(); + // check if the activation time has expired. + let now = Utc::now(); + if now - plugin_state.activation_timestamp + > Duration::seconds(DEFAULT_PLUGIN_ACTIVATION_TIMEOUT) + { + return (pending_requests, true); + } else { + return (pending_requests, false); + } + } + (Vec::new(), false) + } + + pub fn get_all_pending_broker_requests(&self, plugin_name: String) -> Vec { + let status = self.status.read().unwrap(); + if let Some(plugin_state) = status.get(&plugin_name) { + plugin_state.pending_requests.clone() + } else { + Vec::new() + } + } + + pub fn clear_all_pending_broker_requests(&self, plugin_name: String) { + let mut status = self.status.write().unwrap(); + if let Some(plugin_state) = status.get_mut(&plugin_name) { + plugin_state.pending_requests.clear(); + } + } + + pub fn get_status(&self, plugin_name: String) -> Option { + let status = self.status.read().unwrap(); + status.get(&plugin_name).cloned() + } + + pub fn generate_plugin_activation_request(&self, plugin_name: String) -> String { + let id = get_next_id(); + let controller_call_sign = Self::get_controller_call_sign(); + + let request = json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}activate", controller_call_sign), + "params": json!({ + "callsign": plugin_name, + }) + }) + .to_string(); + // Add this request to the inprogress_plugins_request + self.add_thunder_request_to_inprogress_list(id, request.clone()); + request + } + + pub fn generate_plugin_status_request(&self, plugin_name: String) -> String { + let id = get_next_id(); + let controller_call_sign = Self::get_controller_call_sign(); + + let request = json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}status@{}", controller_call_sign, plugin_name), + }) + .to_string(); + // Add this request to the inprogress_plugins_request + self.add_thunder_request_to_inprogress_list(id, request.clone()); + request + } + + pub fn generate_state_change_subscribe_request(&self) -> String { + let id = get_next_id(); + let controller_call_sign = Self::get_controller_call_sign(); + + let request = json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}register", controller_call_sign), + "params": json!({ + "event": "statechange", + "id": "thunder.Broker.Controller.events" + }) + }) + .to_string(); + // Add this request to the inprogress_plugins_request + self.add_thunder_request_to_inprogress_list(id, request.clone()); + request + } + + fn add_thunder_request_to_inprogress_list(&self, id: u64, request: String) { + let mut inprogress_plugins_request = self.inprogress_plugins_request.write().unwrap(); + inprogress_plugins_request.insert(id, request); + } + + pub async fn is_controller_response( + &self, + sender: BrokerSender, + callback: BrokerCallback, + result: &[u8], + ) -> bool { + let data = match serde_json::from_slice::(result) { + Ok(data) => data, + Err(_) => return false, + }; + + if let Some(method) = data.method { + info!("is_controller_response Method: {:?}", method); + if method == STATE_CHANGE_EVENT_METHOD { + // intercept the statechange event and update plugin status. + let params = match data.params { + Some(params) => params, + None => return false, + }; + + let event: StateChangeEvent = match serde_json::from_value(params) { + Ok(event) => event, + Err(_) => return false, + }; + + self.update_status(event.callsign.clone(), event.state.clone()); + + if event.state.is_activated() { + // get the pending ThunderAsyncRequest and process. + let (pending_requests, expired) = + self.retrive_pending_broker_requests(event.callsign); + if !pending_requests.is_empty() { + for pending_request in pending_requests { + if expired { + error!("Expired request: {:?}", pending_request); + callback + .send_error(pending_request, RippleError::ServiceError) + .await; + } else { + let _ = sender.send(pending_request).await; + } + } + } + } + + return true; + } + } + + if let Some(id) = data.id { + let inprogress_plugins_request = self.inprogress_plugins_request.read().unwrap(); + return inprogress_plugins_request.contains_key(&id); + } + + false + } + async fn on_activate_response( + &self, + sender: BrokerSender, + callback: BrokerCallback, + data: &JsonRpcApiResponse, + request: &str, + ) { + let result = match &data.result { + Some(result) => result, + None => return, + }; + + let callsign = match request.split("callsign\":").last() { + Some(callsign) => callsign.trim_matches(|c| c == '"' || c == '}'), + None => return, + }; + + let (pending_requests, expired) = + self.retrive_pending_broker_requests(callsign.to_string()); + + if result.is_null() { + self.update_status(callsign.to_string(), State::Activated); + + for pending_request in pending_requests { + if expired { + error!("Expired request: {:?}", pending_request); + callback + .send_error(pending_request, RippleError::ServiceError) + .await; + } else { + let _ = sender.send(pending_request).await; + } + } + } else if let Some(_e) = &data.error { + Self::on_thunder_error_response(self, callback, data, &callsign.to_string()).await; + } + } + + async fn on_status_response( + &self, + sender: BrokerSender, + callback: BrokerCallback, + data: &JsonRpcApiResponse, + request: &str, + ) { + let result = match &data.result { + Some(result) => result, + None => return, + }; + + let callsign = match request.split('@').last() { + Some(callsign) => callsign.trim_matches(|c| c == '"' || c == '}'), + None => return, + }; + + let status_res: Vec = match serde_json::from_value(result.clone()) { + Ok(status_res) => status_res, + Err(_) => { + Self::on_thunder_error_response(self, callback, data, &callsign.to_string()).await; + return; + } + }; + + for status in status_res { + if status.callsign != callsign { + // it's not required to enforce callsign matching. But it's good to log a warning. + // Already chekced the id in the request, so it's safe to ignore this. + warn!( + "Call Sign not matching callsign from response: {:?} callsign : {:?}", + status.callsign, callsign + ); + } + self.update_status(callsign.to_string(), status.to_state()); + + let (pending_requests, expired) = + self.retrive_pending_broker_requests(callsign.to_string()); + + for pending_request in pending_requests { + if expired { + error!("Expired request: {:?}", pending_request); + callback + .send_error(pending_request, RippleError::ServiceError) + .await; + } else { + let _ = sender.send(pending_request).await; + } + } + } + } + + async fn on_thunder_error_response( + &self, + callback: BrokerCallback, + data: &JsonRpcApiResponse, + plugin_name: &String, + ) { + let error = match &data.error { + Some(error) => error, + None => return, + }; + + error!( + "Error Received from Thunder on getting the status of the plugin: {:?}", + error + ); + + let thunder_error: ThunderError = match serde_json::from_value(error.clone()) { + Ok(error) => error, + Err(_) => return, + }; + + let state = thunder_error.get_state(); + self.update_status(plugin_name.to_string(), state.clone()); + + if state.is_unavailable() { + let (pending_requests, _) = + self.retrive_pending_broker_requests(plugin_name.to_string()); + + for pending_request in pending_requests { + callback + .send_error(pending_request, RippleError::ServiceError) + .await; + } + } + } + + pub fn get_from_inprogress_plugins_request_list(&self, id: u64) -> Option { + let inprogress_plugins_request = self.inprogress_plugins_request.read().unwrap(); + inprogress_plugins_request.get(&id).cloned() + } + + pub async fn handle_controller_response( + &self, + sender: BrokerSender, + callback: BrokerCallback, + result: &[u8], + ) { + let data = match serde_json::from_slice::(result) { + Ok(data) => data, + Err(_) => return, + }; + + let id = match data.id { + Some(id) => id, + None => return, + }; + + let request = match self.get_from_inprogress_plugins_request_list(id) { + Some(request) => request, + None => return, + }; + + if request.contains("Controller.1.activate") { + // handle activate response + self.on_activate_response(sender, callback, &data, &request) + .await; + } else if request.contains("Controller.1.status@") { + // handle status response + self.on_status_response(sender, callback, &data, &request) + .await; + } else if request.contains("Controller.1.register") { + // nothing to do here + info!("StatusManger Received response for register request"); + } + + let mut inprogress_plugins_request = self.inprogress_plugins_request.write().unwrap(); + inprogress_plugins_request.remove(&id); + } +} + +impl BrokerCallback { + /// Default method used for sending errors via the BrokerCallback + pub async fn send_error(&self, request: ThunderAsyncRequest, error: RippleError) { + // TODO + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ripple_sdk::tokio::{ + self, + sync::mpsc::{self, channel}, + }; + + #[test] + fn test_generate_state_change_subscribe_request() { + let status_manager = StatusManager::new(); + let request = status_manager.generate_state_change_subscribe_request(); + assert!(request.contains("register")); + assert!(request.contains("statechange")); + } + + #[tokio::test] + async fn test_on_activate_response() { + let status_manager = StatusManager::new(); + let (tx, _tr) = mpsc::channel(10); + let broker = BrokerSender { sender: tx }; + + let (tx_1, _tr_1) = channel(2); + let callback = BrokerCallback { sender: tx_1 }; + + let data = JsonRpcApiResponse { + id: Some(1), + jsonrpc: "2.0".to_string(), + result: Some(serde_json::json!(null)), + error: None, + method: None, + params: None, + }; + let request = r#"{"jsonrpc":"2.0","id":1,"method":"Controller.1.activate","params":{"callsign":"TestPlugin"}}"#; + status_manager + .on_activate_response(broker, callback, &data, request) + .await; + let status = status_manager.get_status("TestPlugin".to_string()); + assert_eq!(status.unwrap().state, State::Activated); + } + + #[tokio::test] + async fn test_on_status_response() { + let status_manager = StatusManager::new(); + let (tx, _tr) = mpsc::channel(10); + let broker = BrokerSender { sender: tx }; + + let (tx_1, _tr_1) = channel(2); + let callback = BrokerCallback { sender: tx_1 }; + + let data = JsonRpcApiResponse { + id: Some(1), + jsonrpc: "2.0".to_string(), + result: Some(serde_json::json!([{"callsign":"TestPlugin","state":"activated"}])), + error: None, + method: None, + params: None, + }; + let request = r#"{"jsonrpc":"2.0","id":1,"method":"Controller.1.status@TestPlugin"}"#; + status_manager + .on_status_response(broker, callback, &data, request) + .await; + let status = status_manager.get_status("TestPlugin".to_string()); + assert_eq!(status.unwrap().state, State::Activated); + } + + #[tokio::test] + async fn test_on_thunder_error_response() { + let status_manager = StatusManager::new(); + + let (tx_1, _tr_1) = channel(2); + let callback = BrokerCallback { sender: tx_1 }; + + let data = JsonRpcApiResponse { + id: Some(1), + jsonrpc: "2.0".to_string(), + result: None, + error: Some(serde_json::json!({"code":1,"message":"ERROR_UNKNOWN_KEY"})), + method: None, + params: None, + }; + let plugin_name = "TestPlugin".to_string(); + status_manager + .on_thunder_error_response(callback, &data, &plugin_name) + .await; + let status = status_manager.get_status("TestPlugin".to_string()); + assert_eq!(status.unwrap().state, State::Missing); + } + + // Uncomment and use the following unit test only for local testing. Not use as part of the CI/CD pipeline. + /* + use ripple_sdk::{ + api::gateway::rpc_gateway_api::{ApiProtocol, CallContext, RpcRequest}, + }; + use crate::broker::rules_engine::{Rule, RuleTransform}; + #[tokio::test] + async fn test_expired_broker_request() { + let status_manager = StatusManager::new(); + let (tx, _tr) = mpsc::channel(10); + let broker = BrokerSender { sender: tx }; + let (tx_1, _tr_1) = channel(2); + let callback = BrokerCallback { sender: tx_1 }; + let data = JsonRpcApiResponse { + id: Some(1), + jsonrpc: "2.0".to_string(), + result: Some(serde_json::json!(null)), + error: None, + method: None, + params: None, + }; + let request = r#"{"jsonrpc":"2.0","id":1,"method":"Controller.1.activate","params":{"callsign":"TestPlugin"}}"#; + status_manager + .on_activate_response(broker, callback, &data, request) + .await; + let status = status_manager.get_status("TestPlugin".to_string()); + assert_eq!(status.unwrap().state, State::Activated); + let ctx = CallContext::new( + "session_id".to_string(), + "request_id".to_string(), + "app_id".to_string(), + 1, + ApiProtocol::Bridge, + "method".to_string(), + Some("cid".to_string()), + true, + ); + // Add a request to the pending list + let request = DeviceChannelRequest { + rpc: RpcRequest { + ctx, + params_json: "".to_string(), + method: "TestPlugin".to_string(), + }, + rule: Rule { + alias: "TestPlugin".to_string(), + transform: RuleTransform::default(), + endpoint: None, + }, + subscription_processed: None, + }; + status_manager.add_broker_request_to_pending_list("TestPlugin".to_string(), request); + // Sleep for 10 seconds to expire the request + tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + // Check if the request is expired + let (pending_requests, expired) = + status_manager.retrive_pending_broker_requests("TestPlugin".to_string()); + assert_eq!(expired, true); + assert_eq!(pending_requests.len(), 1); + } + */ +} diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index 03a9a3cc9..cf0480ed0 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -18,9 +18,12 @@ pub mod client { pub mod jsonrpc_method_locator; pub mod plugin_manager; + pub mod thunder_async_client; pub mod thunder_client; + pub mod thunder_client2; pub mod thunder_client_pool; pub mod thunder_plugin; + pub mod thunder_plugins_status_mgr; } pub mod bootstrap { diff --git a/device/thunder_ripple_sdk/src/thunder_state.rs b/device/thunder_ripple_sdk/src/thunder_state.rs index 700b01d64..19cabb76f 100644 --- a/device/thunder_ripple_sdk/src/thunder_state.rs +++ b/device/thunder_ripple_sdk/src/thunder_state.rs @@ -60,10 +60,10 @@ impl ThunderConnectionState { #[derive(Debug, Clone)] pub struct ThunderBootstrapStateWithConfig { pub extn_client: ExtnClient, - pub url: Url, - pub pool_size: u32, - pub plugin_param: ThunderPluginBootParam, - pub thunder_connection_state: Arc, + pub url: Option, + pub pool_size: Option, + pub plugin_param: Option, + pub thunder_connection_state: Option>, } #[derive(Debug, Clone)] diff --git a/device/thunder_ripple_sdk/src/utils.rs b/device/thunder_ripple_sdk/src/utils.rs index a9d38a7ef..e5de2aef4 100644 --- a/device/thunder_ripple_sdk/src/utils.rs +++ b/device/thunder_ripple_sdk/src/utils.rs @@ -15,7 +15,10 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::atomic::{AtomicU64, Ordering}, +}; use jsonrpsee::core::Error; use ripple_sdk::{ @@ -109,3 +112,10 @@ pub fn get_error_value(error: &Error) -> Value { } Value::Null } + +static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); + +pub fn get_next_id() -> u64 { + ATOMIC_ID.fetch_add(1, Ordering::Relaxed); + ATOMIC_ID.load(Ordering::Relaxed) +} From 5ac3fba958204c385a7461a0e1afee1c250a67c1 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 8 Nov 2024 12:43:02 +0530 Subject: [PATCH 02/51] fix: compilation warnings fixed. --- .../src/bootstrap/setup_thunder_pool_step.rs | 4 ++-- device/thunder_ripple_sdk/src/client/thunder_client.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs index b2bd0c743..247c62953 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs @@ -85,7 +85,7 @@ impl ThunderPoolStep { ); loop { let failed_plugins = PluginManager::activate_mandatory_plugins( - expected_plugins.unwrap(), + expected_plugins.as_ref().unwrap().clone(), plugin_manager_tx.clone(), ) .await; @@ -106,7 +106,7 @@ impl ThunderPoolStep { url.clone().unwrap(), Some(plugin_manager_tx), thunder_connection_state.clone(), - pool_size - Some(1), + pool_size.unwrap() - 1, ) .await; diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 28df6980d..1bf80d24d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -582,7 +582,7 @@ impl ThunderClientBuilder { if !use_thndbroker { let id = Uuid::new_v4(); - if let Some(url) = url { + if let Some(ref url) = url { info!("initiating thunder connection {}", url); } else { error!("URL is None, cannot initiate thunder connection"); @@ -593,7 +593,7 @@ impl ThunderClientBuilder { let (s, mut r) = mpsc::channel::(32); let pmtx_c = plugin_manager_tx.clone(); let client = match url { - Some(ref url) => { + Some(url) => { Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()) .await } From 6dc75b7e9644c189690ddb799c2fac64cc7fda29 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 8 Nov 2024 16:52:39 +0530 Subject: [PATCH 03/51] chore: added new field calledd "use_thunderbroker" to use as switch between thunderclient and thunderbroker --- .../thunder_ripple_sdk/src/client/thunder_client.rs | 12 ++++++++---- .../src/client/thunder_client_pool.rs | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 1bf80d24d..2c18e3f64 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -190,10 +190,11 @@ impl ThunderMessage { pub struct ThunderClient { pub sender: Option>, pub pooled_sender: Option>, - pub id: Option, + pub id: Uuid, pub plugin_manager_tx: Option>, pub subscriptions: Option>>>, pub thndr_asynclient: Option, + pub use_thunderbroker: bool, } #[derive(Debug, Serialize, Deserialize)] @@ -704,10 +705,11 @@ impl ThunderClientBuilder { Ok(ThunderClient { sender: Some(s), pooled_sender: None, - id: Some(id), + id: id, plugin_manager_tx: pmtx_c, subscriptions: Some(subscriptions), thndr_asynclient: None, + use_thunderbroker: false, }) } else { let (sender, tr) = mpsc::channel(10); @@ -717,10 +719,11 @@ impl ThunderClientBuilder { let thunder_client = ThunderClient { sender: None, pooled_sender: None, - id: None, + id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, thndr_asynclient: Some(client), // client, + use_thunderbroker: true, }; ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); Ok(thunder_client) @@ -732,10 +735,11 @@ impl ThunderClientBuilder { ThunderClient { sender: Some(sender), pooled_sender: None, - id: Some(Uuid::new_v4()), + id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, thndr_asynclient: None, + use_thunderbroker: false, } } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index fca9b6da8..100329661 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -129,7 +129,7 @@ impl ThunderClientPool { ThunderPoolCommand::ResetThunderClient(client_id) => { // Remove the given client and then start a new one to replace it let mut itr = pool.clients.iter(); - let i = itr.position(|x| x.client.id == Some(client_id)); + let i = itr.position(|x| x.client.id == client_id); if let Some(index) = i { let client = ThunderClientBuilder::get_client( Some(url.clone()), @@ -158,10 +158,11 @@ impl ThunderClientPool { Ok(ThunderClient { sender: None, pooled_sender: Some(s), - id: Some(Uuid::new_v4()), + id: Uuid::new_v4(), plugin_manager_tx: pmtx_c, subscriptions: None, thndr_asynclient: None, + use_thunderbroker: false, }) } From 84fd20d71db10bd4569ba05155472fb092c5030c Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 8 Nov 2024 19:56:28 +0530 Subject: [PATCH 04/51] feat : thunderbroker migration changes added, no compilation errors. --- .../src/bootstrap/boot_thunder.rs | 32 +---- .../src/client/thunder_client.rs | 134 +++++++++++++----- .../src/client/thunder_client_pool.rs | 2 + device/thunder_ripple_sdk/src/lib.rs | 1 - 4 files changed, 102 insertions(+), 67 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 07e01274c..100e8d014 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -29,37 +29,6 @@ use crate::client::thunder_client::ThunderClientBuilder; use crate::thunder_state::ThunderBootstrapStateWithConfig; use crate::thunder_state::ThunderState; -// pub async fn boot_thunder( -// ext_client: ExtnClient, -// plugin_param: ThunderPluginBootParam, -// ) -> Option { -// info!("Booting thunder"); -// if ext_client.get_bool_config("use_with_thunder_broker") { -// info!("Using thunder broker"); - -// if let Ok(thndr_client) = ThunderClientBuilder::get_client(None, None, None, None, None, true) -// .await{ -// let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); -// } - -// None -// } else { -// if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { -// if let Ok(state) = ThunderPoolStep::setup(state).await { -// SetupThunderProcessor::setup(state.clone()).await; -// return Some(state); -// } else { -// error!("Unable to connect to Thunder, error in ThunderPoolStep"); -// } -// } else { -// error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); -// } -// None -// } -// } - -use std::sync::Arc; - pub async fn boot_thunder( ext_client: ExtnClient, plugin_param: ThunderPluginBootParam, @@ -85,6 +54,7 @@ pub async fn boot_thunder( prev: thndr_boot_statecfg, state: thunder_state, }; + SetupThunderProcessor::setup(thndr_boot_stateclient.clone()).await; return Some(thndr_boot_stateclient); } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 2c18e3f64..783e0b0cf 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -63,9 +63,13 @@ use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; +use ripple_sdk::api::device::device_operator::DeviceChannelRequest; use ripple_sdk::tokio::sync::mpsc::Receiver; +use std::sync::RwLock; use std::{env, process::Command}; +pub type BrokerSubMap = HashMap>>; + #[derive(Debug)] pub struct ThunderClientManager; @@ -194,6 +198,9 @@ pub struct ThunderClient { pub plugin_manager_tx: Option>, pub subscriptions: Option>>>, pub thndr_asynclient: Option, + pub broker_subscriptions: Option>>, + pub broker_callbacks: + Option>>>>>, pub use_thunderbroker: bool, } @@ -222,20 +229,38 @@ impl ThunderClient { #[async_trait] impl DeviceOperator for ThunderClient { async fn call(&self, request: DeviceCallRequest) -> DeviceResponseMessage { - let (tx, rx) = oneshot::channel::(); - let message = ThunderMessage::ThunderCallMessage(ThunderCallMessage { - method: request.method, - params: request.params, - callback: tx, - }); - self.send_message(message).await; + if !self.use_thunderbroker { + let (tx, rx) = oneshot::channel::(); + let message = ThunderMessage::ThunderCallMessage(ThunderCallMessage { + method: request.method, + params: request.params, + callback: tx, + }); + self.send_message(message).await; + + match rx.await { + Ok(response) => response, + Err(_) => DeviceResponseMessage { + message: Value::Null, + sub_id: None, + }, + } + } else { + let (tx, rx) = oneshot::channel::(); + let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); + self.add_to_callback(&async_request); - match rx.await { - Ok(response) => response, - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, + if let Some(async_client) = &self.thndr_asynclient { + async_client.send(async_request).await; + } + + match rx.await { + Ok(response) => response, + Err(_) => DeviceResponseMessage { + message: Value::Null, + sub_id: None, + }, + } } } @@ -244,28 +269,49 @@ impl DeviceOperator for ThunderClient { request: DeviceSubscribeRequest, handler: mpsc::Sender, ) -> DeviceResponseMessage { - let (tx, rx) = oneshot::channel::(); - let message = ThunderSubscribeMessage { - module: request.module, - event_name: request.event_name, - params: request.params, - handler, - callback: Some(tx), - sub_id: request.sub_id, - }; - let msg = ThunderMessage::ThunderSubscribeMessage(message); - self.send_message(msg).await; - rx.await.unwrap() + if !self.use_thunderbroker { + let (tx, rx) = oneshot::channel::(); + let message = ThunderSubscribeMessage { + module: request.module, + event_name: request.event_name, + params: request.params, + handler, + callback: Some(tx), + sub_id: request.sub_id, + }; + let msg = ThunderMessage::ThunderSubscribeMessage(message); + self.send_message(msg).await; + rx.await.unwrap() + } else { + if let Some(subscribe_request) = self.check_sub(&request) { + let (tx, rx) = oneshot::channel::(); + self.add_to_callback(&subscribe_request); + + if let Some(async_client) = &self.thndr_asynclient { + async_client.send(subscribe_request).await; + } + rx.await.unwrap() + } else { + DeviceResponseMessage { + message: Value::Null, + sub_id: None, + } + } + } } async fn unsubscribe(&self, request: DeviceUnsubscribeRequest) { - let message = ThunderUnsubscribeMessage { - module: request.module, - event_name: request.event_name, - subscription_id: None, - }; - let msg = ThunderMessage::ThunderUnsubscribeMessage(message); - self.send_message(msg).await; + if !self.use_thunderbroker { + let message = ThunderUnsubscribeMessage { + module: request.module, + event_name: request.event_name, + subscription_id: None, + }; + let msg = ThunderMessage::ThunderUnsubscribeMessage(message); + self.send_message(msg).await; + } else { + // unsubscribe() deprecate + } } } @@ -507,6 +553,18 @@ impl ThunderClient { } None } + + fn add_to_callback(&self, request: &ThunderAsyncRequest) {} + + // if already subscibed updated handlers + fn check_sub(&self, request: &DeviceSubscribeRequest) -> Option { + None + } + + // if only one handler cleanup + fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { + None + } } impl ThunderClientBuilder { @@ -578,9 +636,9 @@ impl ThunderClientBuilder { pool_tx: Option>, thunder_connection_state: Option>, existing_client: Option, - use_thndbroker: bool, + use_thndrbroker: bool, ) -> Result { - if !use_thndbroker { + if !use_thndrbroker { let id = Uuid::new_v4(); if let Some(ref url) = url { @@ -709,6 +767,8 @@ impl ThunderClientBuilder { plugin_manager_tx: pmtx_c, subscriptions: Some(subscriptions), thndr_asynclient: None, + broker_subscriptions: None, + broker_callbacks: None, use_thunderbroker: false, }) } else { @@ -722,7 +782,9 @@ impl ThunderClientBuilder { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - thndr_asynclient: Some(client), // client, + thndr_asynclient: Some(client), + broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), + broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunderbroker: true, }; ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); @@ -739,6 +801,8 @@ impl ThunderClientBuilder { plugin_manager_tx: None, subscriptions: None, thndr_asynclient: None, + broker_subscriptions: None, + broker_callbacks: None, use_thunderbroker: false, } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 100329661..8ee072236 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -162,6 +162,8 @@ impl ThunderClientPool { plugin_manager_tx: pmtx_c, subscriptions: None, thndr_asynclient: None, + broker_subscriptions: None, + broker_callbacks: None, use_thunderbroker: false, }) } diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index cf0480ed0..285bc4212 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -20,7 +20,6 @@ pub mod client { pub mod plugin_manager; pub mod thunder_async_client; pub mod thunder_client; - pub mod thunder_client2; pub mod thunder_client_pool; pub mod thunder_plugin; pub mod thunder_plugins_status_mgr; From 2669a4be668602f7a6998d7a98d7a1ea0737bd79 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 11 Nov 2024 12:42:44 +0530 Subject: [PATCH 05/51] fix: clippy errors fixed --- .../src/bootstrap/boot_thunder.rs | 4 +- .../src/client/thunder_client.rs | 38 +++++++++---------- .../src/client/thunder_plugins_status_mgr.rs | 7 +--- .../contracts/thunder_controller_pacts.rs | 11 ++++-- .../contracts/thunder_device_info_pacts.rs | 20 +++++----- .../thunder_package_manager_pacts.rs | 10 ++--- .../thunder_persistent_store_pacts.rs | 6 +-- .../tests/contracts/thunder_remote_pacts.rs | 4 +- .../src/tests/contracts/thunder_wifi_pacts.rs | 4 +- .../src/tests/mock_thunder_controller.rs | 4 ++ 10 files changed, 56 insertions(+), 52 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 100e8d014..a90a2dbcd 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -34,7 +34,8 @@ pub async fn boot_thunder( plugin_param: ThunderPluginBootParam, ) -> Option { info!("Booting thunder"); - if ext_client.get_bool_config("use_with_thunder_broker") { + //by default enabling the thunderBroker + if !ext_client.get_bool_config("use_with_thunder_broker") { info!("Using thunder broker"); if let Ok(thndr_client) = @@ -57,7 +58,6 @@ pub async fn boot_thunder( SetupThunderProcessor::setup(thndr_boot_stateclient.clone()).await; return Some(thndr_boot_stateclient); } - None } else { if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 783e0b0cf..a7ebe98ff 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -246,7 +246,7 @@ impl DeviceOperator for ThunderClient { }, } } else { - let (tx, rx) = oneshot::channel::(); + let (_tx, rx) = oneshot::channel::(); let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); self.add_to_callback(&async_request); @@ -282,20 +282,18 @@ impl DeviceOperator for ThunderClient { let msg = ThunderMessage::ThunderSubscribeMessage(message); self.send_message(msg).await; rx.await.unwrap() - } else { - if let Some(subscribe_request) = self.check_sub(&request) { - let (tx, rx) = oneshot::channel::(); - self.add_to_callback(&subscribe_request); + } else if let Some(subscribe_request) = self.check_sub(&request) { + let (_tx, rx) = oneshot::channel::(); + self.add_to_callback(&subscribe_request); - if let Some(async_client) = &self.thndr_asynclient { - async_client.send(subscribe_request).await; - } - rx.await.unwrap() - } else { - DeviceResponseMessage { - message: Value::Null, - sub_id: None, - } + if let Some(async_client) = &self.thndr_asynclient { + async_client.send(subscribe_request).await; + } + rx.await.unwrap() + } else { + DeviceResponseMessage { + message: Value::Null, + sub_id: None, } } } @@ -639,7 +637,7 @@ impl ThunderClientBuilder { use_thndrbroker: bool, ) -> Result { if !use_thndrbroker { - let id = Uuid::new_v4(); + let uid = Uuid::new_v4(); if let Some(ref url) = url { info!("initiating thunder connection {}", url); @@ -675,17 +673,17 @@ impl ThunderClientBuilder { if let Some(ptx) = pool_tx { warn!( "Client {} became disconnected, removing from pool message {:?}", - id, message + uid, message ); // Remove the client and then try the message again with a new client - let pool_msg = ThunderPoolCommand::ResetThunderClient(id); + let pool_msg = ThunderPoolCommand::ResetThunderClient(uid); mpsc_send_and_log(&ptx, pool_msg, "ResetThunderClient").await; let pool_msg = ThunderPoolCommand::ThunderMessage(message); mpsc_send_and_log(&ptx, pool_msg, "RetryThunderMessage").await; return; } } - info!("Client {} sending thunder message {:?}", id, message); + info!("Client {} sending thunder message {:?}", uid, message); match message { ThunderMessage::ThunderCallMessage(thunder_message) => { ThunderClient::call( @@ -697,7 +695,7 @@ impl ThunderClientBuilder { } ThunderMessage::ThunderSubscribeMessage(thunder_message) => { ThunderClient::subscribe( - id, + uid, &client, &subscriptions_c, thunder_message, @@ -763,7 +761,7 @@ impl ThunderClientBuilder { Ok(ThunderClient { sender: Some(s), pooled_sender: None, - id: id, + id: uid, plugin_manager_tx: pmtx_c, subscriptions: Some(subscriptions), thndr_asynclient: None, diff --git a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs index 8a2e2b486..fd9b5600d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs @@ -16,10 +16,7 @@ // use std::{ collections::HashMap, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, RwLock, - }, + sync::{Arc, RwLock}, }; use ripple_sdk::{ @@ -63,7 +60,7 @@ pub struct BrokerCallback { impl BrokerCallback { pub async fn send(&self, response: ThunderAsyncResponse) { - if let Err(_) = self.sender.send(response).await { + if (self.sender.send(response).await).is_err() { error!("error returning callback for request") } } 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 e281a52b9..ac0069d17 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 @@ -20,9 +20,14 @@ use std::sync::Arc; use url::Url; async fn initialize_thunder_client(server_url: Url) -> ThunderClient { - ThunderClientPool::start(server_url, None, Arc::new(ThunderConnectionState::new()), 1) - .await - .unwrap() + ThunderClientPool::start( + server_url, + None, + Some(Arc::new(ThunderConnectionState::new())), + 1, + ) + .await + .unwrap() } async fn perform_device_call_request( 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 dfc00f050..498ff23f2 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 @@ -89,7 +89,7 @@ async fn test_device_get_info_mac_address() { // Creating thunder client with mock server url let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -223,7 +223,7 @@ async fn test_device_get_interfaces_wifi() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -288,7 +288,7 @@ async fn test_device_get_interfaces_ethernet() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -342,7 +342,7 @@ async fn test_device_get_audio() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -395,7 +395,7 @@ async fn test_device_get_hdcp_supported() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -457,7 +457,7 @@ async fn test_device_get_hdcp_status() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -509,7 +509,7 @@ async fn test_device_get_hdr() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -559,7 +559,7 @@ async fn test_device_get_screen_resolution_without_port() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -607,7 +607,7 @@ async fn test_device_get_make() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -668,7 +668,7 @@ async fn test_device_get_video_resolution() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); 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 0d7e64f1a..aab82e50b 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 @@ -129,7 +129,7 @@ async fn test_install_app( let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -260,7 +260,7 @@ async fn test_uninstall_app( let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -346,7 +346,7 @@ async fn test_get_installed_apps() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -499,7 +499,7 @@ async fn test_init() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -634,7 +634,7 @@ async fn test_get_firebolt_permissions() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); 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 6da52fadd..a4d8e7f64 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 @@ -131,7 +131,7 @@ async fn test_device_set_persistent_value(with_scope: bool) { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -218,7 +218,7 @@ async fn test_device_get_persistent_value(with_scope: bool) { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -303,7 +303,7 @@ async fn test_device_delete_persistent_value_by_key(with_scope: bool) { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_remote_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_remote_pacts.rs index 506305599..09c7c5533 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_remote_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_remote_pacts.rs @@ -91,7 +91,7 @@ async fn test_device_remote_start_pairing() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -180,7 +180,7 @@ async fn test_device_remote_network_status() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); diff --git a/device/thunder_ripple_sdk/src/tests/contracts/thunder_wifi_pacts.rs b/device/thunder_ripple_sdk/src/tests/contracts/thunder_wifi_pacts.rs index 7f51ee1ae..2fb8d895f 100644 --- a/device/thunder_ripple_sdk/src/tests/contracts/thunder_wifi_pacts.rs +++ b/device/thunder_ripple_sdk/src/tests/contracts/thunder_wifi_pacts.rs @@ -69,7 +69,7 @@ async fn test_device_scan_wifi() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -132,7 +132,7 @@ async fn test_device_connect_wifi() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); 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 ec2183cc7..8f19d0a74 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -173,6 +173,10 @@ impl MockThunderController { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, + thndr_asynclient: None, + broker_subscriptions: None, + broker_callbacks: None, + use_thunderbroker: false, }; let (s, r) = unbounded(); From b6d055b887f9953a7c3ef3d945dce3ad0356cff0 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 11 Nov 2024 13:04:14 +0530 Subject: [PATCH 06/51] fix: clippy errors fixed --- .../src/client/thunder_client_pool.rs | 10 +++++++--- .../src/processors/thunder_package_manager.rs | 8 ++++++++ .../contracts/thunder_device_info_pacts.rs | 18 +++++++++--------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 8ee072236..2b5c12d9c 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -262,9 +262,13 @@ mod tests { // Test cases // 1. create a client pool of size 4 - let client = - ThunderClientPool::start(url, Some(tx), Arc::new(ThunderConnectionState::new()), 4) - .await; + let client = ThunderClientPool::start( + url, + Some(tx), + Some(Arc::new(ThunderConnectionState::new())), + 4, + ) + .await; assert!(client.is_ok()); let client = client.unwrap(); 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 73acf1f29..0faba38b6 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -1132,6 +1132,10 @@ pub mod tests { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, + broker_callbacks: None, + broker_subscriptions: None, + thndr_asynclient: None, + use_thunderbroker: false, }; let mut sessions: HashMap = HashMap::new(); sessions.insert("asdf".to_string(), operation.clone()); @@ -1165,6 +1169,10 @@ pub mod tests { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, + broker_callbacks: None, + broker_subscriptions: None, + thndr_asynclient: None, + use_thunderbroker: false, }; let mut sessions: HashMap = HashMap::new(); sessions.insert("asdf".to_string(), operation.clone()); 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 498ff23f2..d48d8c0a9 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 @@ -158,7 +158,7 @@ async fn test_device_get_model() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -778,7 +778,7 @@ async fn test_device_get_timezone() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -850,7 +850,7 @@ async fn test_device_get_available_timezone() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -906,7 +906,7 @@ async fn test_device_get_voice_guidance_enabled() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -984,7 +984,7 @@ async fn test_device_get_voice_guidance_speed() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -1042,7 +1042,7 @@ async fn test_device_set_timezone() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -1098,7 +1098,7 @@ async fn test_device_set_voice_guidance() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -1154,7 +1154,7 @@ async fn test_device_set_voice_guidance_speed() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); @@ -1211,7 +1211,7 @@ async fn test_device_get_internet() { let url = url::Url::parse(mock_server.path("/jsonrpc").as_str()).unwrap(); let thunder_client = - ThunderClientPool::start(url, None, Arc::new(ThunderConnectionState::new()), 1) + ThunderClientPool::start(url, None, Some(Arc::new(ThunderConnectionState::new())), 1) .await .unwrap(); From 555825650a4434cffa0b51f89df8a55e0e6fa4bb Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 11 Nov 2024 13:32:55 +0530 Subject: [PATCH 07/51] fix: clippy error fixed --- device/thunder_ripple_sdk/src/client/thunder_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index a7ebe98ff..e5812f9af 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -69,6 +69,7 @@ use std::sync::RwLock; use std::{env, process::Command}; pub type BrokerSubMap = HashMap>>; +pub type BrokerCallbackMap = HashMap>>; #[derive(Debug)] pub struct ThunderClientManager; @@ -199,8 +200,7 @@ pub struct ThunderClient { pub subscriptions: Option>>>, pub thndr_asynclient: Option, pub broker_subscriptions: Option>>, - pub broker_callbacks: - Option>>>>>, + pub broker_callbacks: Option>>, pub use_thunderbroker: bool, } From 9bbc4314d41c6bb5bdd5f2cd336f27dd2a0660cc Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 12 Nov 2024 13:16:44 +0530 Subject: [PATCH 08/51] chore: deleted the unnecessary file "thunder_client2.rs" --- .../src/client/thunder_async_client.rs | 6 +- .../src/client/thunder_client.rs | 7 +- .../src/client/thunder_client2.rs | 157 ------------------ .../src/client/thunder_plugins_status_mgr.rs | 6 +- 4 files changed, 15 insertions(+), 161 deletions(-) delete mode 100644 device/thunder_ripple_sdk/src/client/thunder_client2.rs diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 563d0df24..58d0bf4ec 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -302,5 +302,9 @@ impl ThunderAsyncClient { } } - pub async fn send(&self, request: ThunderAsyncRequest) {} + pub async fn send(&self, request: ThunderAsyncRequest) { + if let Err(e) = self.sender.send(request).await { + error!("Failed to send thunder Async Request: {:?}", e); + } + } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index e5812f9af..99fb87ddc 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -552,11 +552,14 @@ impl ThunderClient { None } - fn add_to_callback(&self, request: &ThunderAsyncRequest) {} + fn add_to_callback(&self, request: &ThunderAsyncRequest) { + let mut callbacks = self.broker_callbacks.as_ref().unwrap().write().unwrap(); + callbacks.insert(request.id, None); + } // if already subscibed updated handlers fn check_sub(&self, request: &DeviceSubscribeRequest) -> Option { - None + let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().read().unwrap(); } // if only one handler cleanup diff --git a/device/thunder_ripple_sdk/src/client/thunder_client2.rs b/device/thunder_ripple_sdk/src/client/thunder_client2.rs deleted file mode 100644 index 04babdea9..000000000 --- a/device/thunder_ripple_sdk/src/client/thunder_client2.rs +++ /dev/null @@ -1,157 +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; -use ripple_sdk::api::device::device_operator::DeviceChannelRequest; -use ripple_sdk::api::device::device_operator::DeviceOperator; -use ripple_sdk::log::error; -use ripple_sdk::tokio::sync::mpsc::Receiver; - -use ripple_sdk::{ - api::device::device_operator::DeviceResponseMessage, - tokio::sync::mpsc::{self, Sender as MpscSender}, -}; - -use ripple_sdk::{ - api::device::device_operator::{ - DeviceCallRequest, DeviceSubscribeRequest, DeviceUnsubscribeRequest, - }, - serde_json::Value, - tokio, -}; - -use ripple_sdk::{ - tokio::sync::oneshot::{self, Sender as OneShotSender}, - utils::error::RippleError, -}; - -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; - -use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; -use super::thunder_plugins_status_mgr::BrokerCallback; - -pub struct ThunderClientBuilder; - -pub type BrokerSubMap = HashMap>>; - -#[derive(Debug, Clone)] -pub struct ThunderClient { - client: ThunderAsyncClient, - subscriptions: Arc>, - callbacks: Arc>>>>, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct DefaultThunderResult { - pub success: bool, -} - -impl ThunderClient { - fn add_to_callback(&self, request: &ThunderAsyncRequest) {} - - // if already subscibed updated handlers - fn check_sub(&self, request: &DeviceSubscribeRequest) -> Option { - None - } - - // if only one handler cleanup - fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { - None - } -} - -#[async_trait] -impl DeviceOperator for ThunderClient { - async fn call(&self, request: DeviceCallRequest) -> DeviceResponseMessage { - let (tx, rx) = oneshot::channel::(); - let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); - self.add_to_callback(&async_request); - self.client.send(async_request).await; - match rx.await { - Ok(response) => response, - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, - } - } - - async fn subscribe( - &self, - request: DeviceSubscribeRequest, - handler: mpsc::Sender, - ) -> DeviceResponseMessage { - if let Some(subscribe_request) = self.check_sub(&request) { - let (tx, rx) = oneshot::channel::(); - self.add_to_callback(&subscribe_request); - self.client.send(subscribe_request).await; - rx.await.unwrap() - } else { - DeviceResponseMessage { - message: Value::Null, - sub_id: None, - } - } - } - - async fn unsubscribe(&self, request: DeviceUnsubscribeRequest) { - // deprecate - } -} - -#[derive(Debug)] -pub struct ThunderClientManager; - -impl ThunderClientManager { - fn manage( - client: ThunderClient, - mut request_tr: Receiver, - mut response_tr: Receiver, - ) { - let client_c = client.clone(); - tokio::spawn(async move { - loop { - request_tr = client_c.client.start("", request_tr).await; - error!("Thunder disconnected so reconnecting") - } - }); - - tokio::spawn(async move { - while let Some(v) = response_tr.recv().await { - // check with thunder client callbacks and subscriptions - } - }); - } -} - -impl ThunderClientBuilder { - pub async fn get_client() -> Result { - let (sender, tr) = mpsc::channel(10); - let callback = BrokerCallback { sender }; - let (broker_tx, broker_rx) = mpsc::channel(10); - let client = ThunderAsyncClient::new(callback, broker_tx); - let thunder_client = ThunderClient { - client, - subscriptions: Arc::new(RwLock::new(HashMap::new())), - callbacks: Arc::new(RwLock::new(HashMap::new())), - }; - ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); - Ok(thunder_client) - } -} diff --git a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs index fd9b5600d..96d9eca98 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs @@ -552,7 +552,11 @@ impl StatusManager { impl BrokerCallback { /// Default method used for sending errors via the BrokerCallback pub async fn send_error(&self, request: ThunderAsyncRequest, error: RippleError) { - // TODO + let response = ThunderAsyncResponse { + id: Some(request.id), + result: Err(error), + }; + self.send(response).await; } } From 8e6ccd9a9841d3d00df5a579030bcea248d45184 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 13 Nov 2024 19:49:20 +0530 Subject: [PATCH 09/51] fix: modified the thunder_client::manage() method --- .../src/client/thunder_client.rs | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 99fb87ddc..5961c675d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -22,6 +22,8 @@ use std::sync::Arc; use jsonrpsee::core::client::{Client, ClientT, SubscriptionClientT}; use jsonrpsee::ws_client::WsClientBuilder; +use crate::thunder_state::ThunderConnectionState; +use crate::utils::get_error_value; use jsonrpsee::core::{async_trait, error::Error as JsonRpcError}; use jsonrpsee::types::ParamsSer; use regex::Regex; @@ -53,9 +55,6 @@ use ripple_sdk::{ use serde::{Deserialize, Serialize}; use url::Url; -use crate::thunder_state::ThunderConnectionState; -use crate::utils::get_error_value; - use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; use super::thunder_client_pool::ThunderPoolCommand; use super::thunder_plugins_status_mgr::BrokerCallback; @@ -77,26 +76,20 @@ pub struct ThunderClientManager; impl ThunderClientManager { fn manage( client: ThunderClient, - mut request_tr: Receiver, - mut response_tr: Receiver, + request_tr: Receiver, + _response_tr: Receiver, ) { let client_c = client.clone(); - tokio::spawn(async move { - loop { - if let Some(thndr_asynclient) = &client_c.thndr_asynclient { - request_tr = thndr_asynclient.start("", request_tr).await; - } - error!("Thunder disconnected so reconnecting") - } - }); tokio::spawn(async move { - while let Some(v) = response_tr.recv().await { - // check with thunder client callbacks and subscriptions + if let Some(thndr_asynclient) = &client_c.thndr_asynclient { + thndr_asynclient.start("", request_tr).await; } + error!("Thunder disconnected so reconnecting"); }); } } + pub struct ThunderClientBuilder; #[derive(Debug)] @@ -282,7 +275,7 @@ impl DeviceOperator for ThunderClient { let msg = ThunderMessage::ThunderSubscribeMessage(message); self.send_message(msg).await; rx.await.unwrap() - } else if let Some(subscribe_request) = self.check_sub(&request) { + } else if let Some(subscribe_request) = self.check_sub(&request, handler.clone()) { let (_tx, rx) = oneshot::channel::(); self.add_to_callback(&subscribe_request); @@ -558,14 +551,28 @@ impl ThunderClient { } // if already subscibed updated handlers - fn check_sub(&self, request: &DeviceSubscribeRequest) -> Option { - let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().read().unwrap(); + fn check_sub( + &self, + request: &DeviceSubscribeRequest, + handler: MpscSender, + ) -> Option { + let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); + let key = format!("{}.{}", request.module, request.event_name); + if let Some(subs) = broker_subscriptions.get_mut(&key) { + subs.push(handler); + None + } else { + let async_request = + ThunderAsyncRequest::new(DeviceChannelRequest::Subscribe(request.clone())); + broker_subscriptions.insert(key, vec![handler]); + Some(async_request) + } } // if only one handler cleanup - fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { - None - } + // fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { + // None + // } } impl ThunderClientBuilder { @@ -788,7 +795,9 @@ impl ThunderClientBuilder { broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunderbroker: true, }; + ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); + Ok(thunder_client) } } From 6566a42eba0e36a3fe8034205dac807c37d4ce10 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 14 Nov 2024 22:48:58 +0530 Subject: [PATCH 10/51] feat: updated the method of ThunderClientManager::manage() --- .../src/client/thunder_async_client.rs | 20 +++++++++++- .../src/client/thunder_client.rs | 31 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 58d0bf4ec..f0c92f17e 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -19,6 +19,7 @@ use std::time::Duration; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; +use ripple_sdk::api::device::device_operator::DeviceResponseMessage; use ripple_sdk::{ api::{ device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, @@ -31,7 +32,6 @@ use ripple_sdk::{ }, utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; - use serde_json::json; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; @@ -81,6 +81,24 @@ impl ThunderAsyncResponse { result: Err(e), } } + + pub fn get_event(&self) -> Option { + if let Ok(e) = &self.result { + return e.method.clone(); + } + None + } + + pub fn get_device_resp_msg(&self) -> Option { + if let Ok(device_resp) = &self.result { + if let Ok(res) = serde_json::to_value(device_resp) { + if let Ok(device_resp_msg) = serde_json::from_value(res) { + return device_resp_msg; + } + } + } + None + } } impl ThunderAsyncClient { diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 5961c675d..4e131f250 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -77,7 +77,7 @@ impl ThunderClientManager { fn manage( client: ThunderClient, request_tr: Receiver, - _response_tr: Receiver, + mut response_tr: Receiver, ) { let client_c = client.clone(); @@ -87,6 +87,35 @@ impl ThunderClientManager { } error!("Thunder disconnected so reconnecting"); }); + + tokio::spawn(async move { + while let Some(response) = response_tr.recv().await { + if let Some(id) = response.id { + if let Some(cb) = client.clone().broker_callbacks { + let mut callback = cb.write().unwrap(); + if let Some(Some(c)) = callback.remove(&id) { + if let Some(resp) = response.get_device_resp_msg() { + oneshot_send_and_log(c, resp, "ThunderResponse"); + }; + } + } + } else if let Some(event_name) = response.get_event() { + if let Some(broker_subs) = client.clone().broker_subscriptions { + let subs = { + let mut br_subs = broker_subs.write().unwrap(); + br_subs.get_mut(&event_name).cloned() + }; + if let Some(subs) = subs { + for s in subs { + if let Some(resp_msg) = response.get_device_resp_msg() { + mpsc_send_and_log(&s, resp_msg, "ThunderResponse").await; + } + } + } + } + } + } + }); } } From de029ae90d13b168facebb51c1747b283c2517c7 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 15 Nov 2024 17:37:43 +0530 Subject: [PATCH 11/51] chore: added await method for one shot channel communication method --- device/thunder_ripple_sdk/src/client/thunder_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 4e131f250..be5c4146f 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -95,7 +95,7 @@ impl ThunderClientManager { let mut callback = cb.write().unwrap(); if let Some(Some(c)) = callback.remove(&id) { if let Some(resp) = response.get_device_resp_msg() { - oneshot_send_and_log(c, resp, "ThunderResponse"); + oneshot_send_and_log(c, resp, "ThunderResponse").await; }; } } From 1fccdaa48eb926a2fde68d1c65bdddb270037bc9 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 15 Nov 2024 17:57:13 +0530 Subject: [PATCH 12/51] fix: modified the get_device_resp_msg() method. --- .../src/client/thunder_async_client.rs | 20 ++++++++++++------- .../src/client/thunder_client.rs | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index f0c92f17e..fd5659ba7 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -90,14 +90,20 @@ impl ThunderAsyncResponse { } pub fn get_device_resp_msg(&self) -> Option { - if let Ok(device_resp) = &self.result { - if let Ok(res) = serde_json::to_value(device_resp) { - if let Ok(device_resp_msg) = serde_json::from_value(res) { - return device_resp_msg; - } - } + let device_resp = match &self.result { + Ok(resp) => resp, + _ => return None, + }; + + let serialized = match serde_json::to_value(device_resp) { + Ok(val) => val, + Err(_) => return None, + }; + + match serde_json::from_value(serialized) { + Ok(device_resp_msg) => Some(device_resp_msg), + Err(_) => None, } - None } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index be5c4146f..4e131f250 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -95,7 +95,7 @@ impl ThunderClientManager { let mut callback = cb.write().unwrap(); if let Some(Some(c)) = callback.remove(&id) { if let Some(resp) = response.get_device_resp_msg() { - oneshot_send_and_log(c, resp, "ThunderResponse").await; + oneshot_send_and_log(c, resp, "ThunderResponse"); }; } } From 88ff286422bd1233ae1d974953aa835170ea4ee4 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 18 Nov 2024 19:48:03 +0530 Subject: [PATCH 13/51] chore: passing valid url for websocket connection --- device/thunder_ripple_sdk/src/client/thunder_client.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 4e131f250..ec6257fa1 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -83,7 +83,9 @@ impl ThunderClientManager { tokio::spawn(async move { if let Some(thndr_asynclient) = &client_c.thndr_asynclient { - thndr_asynclient.start("", request_tr).await; + thndr_asynclient + .start("ws://127.0.0.1:9998/jsonrpc", request_tr) + .await; } error!("Thunder disconnected so reconnecting"); }); From b52500faa56156b6fcb94b1ba2b0299abe5389bc Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 19 Nov 2024 17:27:55 +0530 Subject: [PATCH 14/51] feat: added the src code to get the platform params for thunderbroker connection --- core/main/src/broker/rules_engine.rs | 17 +++++++ .../src/bootstrap/boot_thunder.rs | 51 ++++++++++++++++++- .../src/client/thunder_client.rs | 10 +++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/core/main/src/broker/rules_engine.rs b/core/main/src/broker/rules_engine.rs index 2c1626bf5..e34c76ae9 100644 --- a/core/main/src/broker/rules_engine.rs +++ b/core/main/src/broker/rules_engine.rs @@ -157,6 +157,23 @@ pub struct RuleEngine { } impl RuleEngine { + // // pub fn get_protocol_endpoint(&self, protocol: &str) -> RuleEndpoint { + // // self.rules + // // .endpoints + // // .get(protocol) + // // .cloned() + // // .expect("protocol rule_endpoint not found!") + // // } + + // pub fn get_protocol_endpoint(&self, protocol: &str) -> Option { + // if let Some(endpoint) = self.rules.endpoints.get(protocol) { + // Some(endpoint.clone()) + // } else { + // error!("Error: Endpoint with protocol '{}' not found", protocol); + // None + // } + // } + fn build_path(path: &str, default_path: &str) -> String { if path.starts_with('/') { path.to_owned() diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index a90a2dbcd..237254a55 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -21,13 +21,31 @@ use crate::{ }; use ripple_sdk::{ extn::client::extn_client::ExtnClient, - log::{error, info}, + log::{debug, error, info, warn}, + serde_json::{self, Error}, }; use super::{get_config_step::ThunderGetConfigStep, setup_thunder_pool_step::ThunderPoolStep}; use crate::client::thunder_client::ThunderClientBuilder; use crate::thunder_state::ThunderBootstrapStateWithConfig; use crate::thunder_state::ThunderState; +use ripple_sdk::api::config::Config; +use ripple_sdk::utils::error::RippleError; +use serde::Deserialize; + +use ripple_sdk::extn::extn_client_message::{ExtnMessage, ExtnResponse}; + +const GATEWAY_DEFAULT: &str = "ws://127.0.0.1:9998/jsonrpc"; + +#[derive(Deserialize, Clone)] +pub struct ThunderPlatformParams { + #[serde(default = "gateway_default")] + gateway: String, +} + +fn gateway_default() -> String { + String::from(GATEWAY_DEFAULT) +} pub async fn boot_thunder( ext_client: ExtnClient, @@ -37,9 +55,38 @@ pub async fn boot_thunder( //by default enabling the thunderBroker if !ext_client.get_bool_config("use_with_thunder_broker") { info!("Using thunder broker"); + let mut extn_client = ext_client.clone(); + let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); + let extn_message_response: Result = + extn_client.request(Config::PlatformParameters).await; + + if let Ok(message) = extn_message_response { + if let Some(ExtnResponse::Value(v)) = message.payload.extract() { + let tp_res: Result = serde_json::from_value(v); + if let Ok(thunder_parameters) = tp_res { + if let Ok(gtway_url) = url::Url::parse(&thunder_parameters.gateway) { + debug!("Got url from device manifest"); + gateway_url = gtway_url + } else { + warn!( + "Could not parse thunder gateway '{}', using default {}", + thunder_parameters.gateway, GATEWAY_DEFAULT + ); + } + } else { + warn!( + "Could not read thunder platform parameters, using default {}", + GATEWAY_DEFAULT + ); + } + if let Ok(host_override) = std::env::var("DEVICE_HOST") { + gateway_url.set_host(Some(&host_override)).ok(); + } + } + } if let Ok(thndr_client) = - ThunderClientBuilder::get_client(None, None, None, None, None, true).await + ThunderClientBuilder::get_client(Some(gateway_url), None, None, None, None, true).await { let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index ec6257fa1..8b0cfb6c2 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -78,13 +78,14 @@ impl ThunderClientManager { client: ThunderClient, request_tr: Receiver, mut response_tr: Receiver, + thndr_endpoint_url: String, ) { let client_c = client.clone(); tokio::spawn(async move { if let Some(thndr_asynclient) = &client_c.thndr_asynclient { thndr_asynclient - .start("ws://127.0.0.1:9998/jsonrpc", request_tr) + .start(&thndr_endpoint_url, request_tr) .await; } error!("Thunder disconnected so reconnecting"); @@ -827,7 +828,12 @@ impl ThunderClientBuilder { use_thunderbroker: true, }; - ThunderClientManager::manage(thunder_client.clone(), broker_rx, tr); + ThunderClientManager::manage( + thunder_client.clone(), + broker_rx, + tr, + url.unwrap().to_string(), + ); Ok(thunder_client) } From 932037c58ecf7d84aa3f87212d0141b9a680012c Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 25 Nov 2024 12:40:58 +0530 Subject: [PATCH 15/51] feat: cleanup fn get_protocol_endpoint() in RuleEngine --- core/main/src/broker/rules_engine.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/core/main/src/broker/rules_engine.rs b/core/main/src/broker/rules_engine.rs index e34c76ae9..2c1626bf5 100644 --- a/core/main/src/broker/rules_engine.rs +++ b/core/main/src/broker/rules_engine.rs @@ -157,23 +157,6 @@ pub struct RuleEngine { } impl RuleEngine { - // // pub fn get_protocol_endpoint(&self, protocol: &str) -> RuleEndpoint { - // // self.rules - // // .endpoints - // // .get(protocol) - // // .cloned() - // // .expect("protocol rule_endpoint not found!") - // // } - - // pub fn get_protocol_endpoint(&self, protocol: &str) -> Option { - // if let Some(endpoint) = self.rules.endpoints.get(protocol) { - // Some(endpoint.clone()) - // } else { - // error!("Error: Endpoint with protocol '{}' not found", protocol); - // None - // } - // } - fn build_path(path: &str, default_path: &str) -> String { if path.starts_with('/') { path.to_owned() From cdb8f31848d1b51b2b8fd26d8d8f69f352aab005 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 26 Nov 2024 11:38:08 +0530 Subject: [PATCH 16/51] fix: clippy warning fixed --- core/main/src/broker/broker_utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 638a5270a..5723ae9d3 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -24,7 +24,6 @@ use ripple_sdk::{ log::{error, info}, tokio::{self, net::TcpStream}, utils::rpc_utils::extract_tcp_port, - uuid::Uuid, }; use serde_json::Value; use std::time::Duration; From 84ad404f18aa5375794b98776da4be12d5225b08 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 3 Dec 2024 21:14:09 +0530 Subject: [PATCH 17/51] fix: modified the thunderbroker flag check based on the config file --- device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 237254a55..11dfaea7d 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -53,7 +53,7 @@ pub async fn boot_thunder( ) -> Option { info!("Booting thunder"); //by default enabling the thunderBroker - if !ext_client.get_bool_config("use_with_thunder_broker") { + if ext_client.get_bool_config("use_with_thunder_broker") { info!("Using thunder broker"); let mut extn_client = ext_client.clone(); let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); From 21cb6f44e2f652023bb5ef10838e6f613ce6c6b0 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 23 Dec 2024 17:29:31 +0530 Subject: [PATCH 18/51] feat: modified the broker subscription handling --- core/sdk/src/api/device/device_operator.rs | 10 + .../src/bootstrap/boot_thunder.rs | 3 + .../src/client/thunder_async_client.rs | 170 ++++++++++++---- .../src/client/thunder_client.rs | 188 +++++++++++++++--- 4 files changed, 299 insertions(+), 72 deletions(-) diff --git a/core/sdk/src/api/device/device_operator.rs b/core/sdk/src/api/device/device_operator.rs index 13d9c3f6f..5fd1fbfd8 100644 --- a/core/sdk/src/api/device/device_operator.rs +++ b/core/sdk/src/api/device/device_operator.rs @@ -143,6 +143,16 @@ impl DeviceResponseMessage { sub_id: Some(sub_id), } } + + pub fn new(message: Value, sub_id: Option) -> DeviceResponseMessage { + DeviceResponseMessage { message, sub_id } + } +} + +#[derive(Debug, Clone)] +pub struct DeviceResponseSubscription { + pub sub_id: Option, + pub handlers: Vec>, } #[cfg(test)] diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 11dfaea7d..ab5891659 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -102,6 +102,9 @@ pub async fn boot_thunder( prev: thndr_boot_statecfg, state: thunder_state, }; + + thndr_boot_stateclient.clone().state.start_event_thread(); + SetupThunderProcessor::setup(thndr_boot_stateclient.clone()).await; return Some(thndr_boot_stateclient); } diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index fd5659ba7..86a5fe9c0 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -25,11 +25,7 @@ use ripple_sdk::{ device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, }, log::{debug, error, info}, - tokio::{ - self, - net::TcpStream, - sync::mpsc::{Receiver, Sender}, - }, + tokio::{self, net::TcpStream, sync::mpsc::Receiver}, utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; use serde_json::json; @@ -89,29 +85,56 @@ impl ThunderAsyncResponse { None } - pub fn get_device_resp_msg(&self) -> Option { - let device_resp = match &self.result { - Ok(resp) => resp, + pub fn get_id(&self) -> Option { + match &self.result { + Ok(response) => response.id, + Err(_) => None, + } + } + + pub fn get_device_resp_msg(&self, sub_id: Option) -> Option { + println!("@@NNA...get_device_resp_msg res:{:?}", self.result); + let json_resp = match &self.result { + Ok(json_resp_res) => { + println!("@@NNA...get_device_resp_msg resp::{:?}", json_resp_res); + json_resp_res + } _ => return None, }; - let serialized = match serde_json::to_value(device_resp) { - Ok(val) => val, - Err(_) => return None, - }; + let mut device_response_msg = None; - match serde_json::from_value(serialized) { - Ok(device_resp_msg) => Some(device_resp_msg), - Err(_) => None, + if let Some(res) = &json_resp.result { + device_response_msg = Some(DeviceResponseMessage::new(res.clone(), sub_id)); + } else if let Some(er) = &json_resp.error { + device_response_msg = Some(DeviceResponseMessage::new(er.clone(), sub_id)); + } else if !json_resp.clone().method.is_none() { + if let Some(params) = &json_resp.params { + let dev_resp = serde_json::to_value(params).unwrap(); + device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); + } + } else { + error!("deviceresponse msg extraction failed."); } + println!("@@NNA...device_response_msg: {:?}", device_response_msg); + device_response_msg } } impl ThunderAsyncClient { + fn get_id_from_result(result: &[u8]) -> Option { + serde_json::from_slice::(result) + .ok() + .and_then(|data| data.id) + } + pub fn get_sender(&self) -> BrokerSender { self.sender.clone() } + pub fn get_thndrasync_callback(&self) -> BrokerCallback { + self.callback.clone() + } async fn create_ws( endpoint: &str, ) -> ( @@ -146,16 +169,28 @@ impl ThunderAsyncClient { } fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result, RippleError> { + println!("@@@NNA-----> in start prepare request id :{}", request.id); let mut requests = Vec::new(); - let id = request.id; + let id: u64 = request.id; let (callsign, method) = request.request.get_callsign_method(); + println!( + "@@@NNA-----> in prepare request callsign :{}, method :{}", + callsign, method + ); if method.is_empty() { return Err(RippleError::InvalidInput); } // check if the plugin is activated. let status = match self.status_manager.get_status(callsign.clone()) { - Some(v) => v.clone(), + Some(v) => { + println!( + "@@@NNA....status_manager.get_status returned some value. v:{:?} ", + v + ); + v.clone() + } None => { + println!("@@@NNA....status_manager.get_status return none."); self.status_manager .add_broker_request_to_pending_list(callsign.clone(), request.clone()); // PluginState is not available with StateManager, create an internal thunder request to activate the plugin @@ -166,6 +201,10 @@ impl ThunderAsyncClient { return Ok(requests); } }; + println!( + "@@@NNA-----> in prepare request ThunderPluginState :{:?} ", + status + ); if status.state.is_missing() { error!("Plugin {} is missing", callsign); @@ -178,6 +217,7 @@ impl ThunderAsyncClient { } if !status.state.is_activated() { + println!("@@@NNA....plugin not activated yet..."); // add the broker request to pending list self.status_manager .add_broker_request_to_pending_list(callsign.clone(), request.clone()); @@ -187,10 +227,21 @@ impl ThunderAsyncClient { .generate_plugin_activation_request(callsign.clone()); requests.push(request.to_string()); return Ok(requests); + } else { + println!("@@@NNA....plugin is activated Now...&&&&&..."); } + println!( + "@@@NNA....after plugin activation devicechannelrequest : {:?} ", + request.request + ); + match &request.request { DeviceChannelRequest::Call(c) => { + println!( + "@@@NNA-----> in DeviceChannelRequest::Call request id :{}", + request.id + ); // Simple request and response handling requests.push( json!({ @@ -202,39 +253,50 @@ impl ThunderAsyncClient { .to_string(), ) } - DeviceChannelRequest::Unsubscribe(_) => requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.unregister", callsign), - "params": { - "event": method, - "id": "client.events" - } - }) - .to_string(), - ), - DeviceChannelRequest::Subscribe(_) => requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.register", callsign), - "params": json!({ - "event": method, - "id": "client.events" + DeviceChannelRequest::Unsubscribe(_) => { + println!( + "@@@NNA-----> in DeviceChannelRequest::Unsubscribe request id :{}", + request.id + ); + requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.unregister", callsign), + "params": { + "event": method, + "id": "client.events" + } }) - }) - .to_string(), - ), + .to_string(), + ) + } + DeviceChannelRequest::Subscribe(_) => { + println!( + "@@@NNA-----> in DeviceChannelRequest::Subscribe request id :{}", + request.id + ); + requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.register", callsign), + "params": json!({ + "event": method, + "id": "client.events" + }) + }) + .to_string(), + ) + } } - Ok(requests) } - pub fn new(callback: BrokerCallback, tx: Sender) -> Self { + pub fn new(callback: BrokerCallback, sender: BrokerSender) -> Self { Self { status_manager: StatusManager::new(), - sender: BrokerSender { sender: tx.clone() }, + sender, callback, } } @@ -265,13 +327,20 @@ impl ThunderAsyncClient { loop { tokio::select! { Some(value) = &mut read => { + debug!("@@@NNA...Got response in thunder async client start"); match value { Ok(v) => { + println!("@@@NNA----> msg v: {:?}",v); if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + println!("@@@NNA----> msg t: {:?}",t); if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { + debug!("@@@NNA---->Got response in thunder async client start before handle_controller_response. sender:{:?}, callback:{:?}",client_c.get_sender(), callback.clone() ); client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; + debug!("@@@NNA---->after step client_c.status_manager.handle_controller_response"); } else { + let id = Self::get_id_from_result(t.as_bytes()); + println!("@@@NNA.... jsn response id:{:?}, callback:{:?}", id, callback.clone()); // send the incoming text without context back to the sender Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await } @@ -286,10 +355,13 @@ impl ThunderAsyncClient { }, Some(request) = tr.recv() => { debug!("Got request from receiver for broker {:?}", request); + debug!("Got request from receiver for broker for method{:?}", request.request.get_callsign_method()); match client_c.prepare_request(&request) { Ok(updated_request) => { debug!("Sending request to broker {:?}", updated_request); for r in updated_request { + println!("@@@NNA----> we r at the feed, flush operations block...."); + println!("@@@NNA----> r :{}", r); let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; let _flush = ws_tx.flush().await; } @@ -304,7 +376,9 @@ impl ThunderAsyncClient { error!("error preparing request {:?}", e) } } - callback_for_sender.send(response).await + println!("@@@NNA----> before callback_for_sender send with response: {:?}", response); + callback_for_sender.send(response).await; + println!("@@@NNA----> after callback_for_sender send "); } } } @@ -317,7 +391,15 @@ impl ThunderAsyncClient { /// Default handler method for the broker to remove the context and send it back to the /// client for consumption async fn handle_jsonrpc_response(result: &[u8], callback: BrokerCallback) { + debug!( + "@@@NNA...in handle_jsonrpc_response with callback: {:?}, result:{:?}", + callback, result + ); if let Ok(message) = serde_json::from_slice::(result) { + debug!( + "@@@NNA...in handle_jsonrpc_response msg:{:?} to callback:{:?}", + message, callback + ); callback .send(ThunderAsyncResponse::new_response(message)) .await diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 8b0cfb6c2..b63d3b06d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -53,21 +53,22 @@ use ripple_sdk::{ utils::error::RippleError, }; use serde::{Deserialize, Serialize}; +use tokio::sync::oneshot::Sender; use url::Url; use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; use super::thunder_client_pool::ThunderPoolCommand; -use super::thunder_plugins_status_mgr::BrokerCallback; +use super::thunder_plugins_status_mgr::{BrokerCallback, BrokerSender}; use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; -use ripple_sdk::api::device::device_operator::DeviceChannelRequest; +use ripple_sdk::api::device::device_operator::{DeviceChannelRequest, DeviceResponseSubscription}; use ripple_sdk::tokio::sync::mpsc::Receiver; use std::sync::RwLock; use std::{env, process::Command}; -pub type BrokerSubMap = HashMap>>; +pub type BrokerSubMap = HashMap; pub type BrokerCallbackMap = HashMap>>; #[derive(Debug)] @@ -84,33 +85,65 @@ impl ThunderClientManager { tokio::spawn(async move { if let Some(thndr_asynclient) = &client_c.thndr_asynclient { + println!("@@@NNA----> from thunder_client to async start call...."); thndr_asynclient .start(&thndr_endpoint_url, request_tr) .await; } error!("Thunder disconnected so reconnecting"); }); - + /*thunder async response will get here */ tokio::spawn(async move { + println!("@@@NNA----> in thunder::manage response block entrance..."); while let Some(response) = response_tr.recv().await { - if let Some(id) = response.id { + println!( + "@@@NNA...manage fn response block..with response{:?}", + response + ); + if let Some(id) = response.get_id() { + println!("@@@NNA...manage fn response id: {:?}", id); if let Some(cb) = client.clone().broker_callbacks { + println!( + "@@@NNA...manage fn broker_callbacks check inside..callback:{:?}", + cb + ); let mut callback = cb.write().unwrap(); + println!( + "@@@NNA.... after cb.write fn unwrap callback: {:?}", + callback + ); if let Some(Some(c)) = callback.remove(&id) { - if let Some(resp) = response.get_device_resp_msg() { + println!("@@@NNA...manage fn after callback.remove.."); + if let Some(resp) = response.get_device_resp_msg(None) { + println!("@@@NNA...deviceresponse {:?}", resp); + println!("@@@NNA...onshot send to sender tx: {:?}", c); oneshot_send_and_log(c, resp, "ThunderResponse"); }; } } } else if let Some(event_name) = response.get_event() { + println!("@@@NNA...manage fn response event {:?}", event_name); if let Some(broker_subs) = client.clone().broker_subscriptions { + println!( + "@@@NNA...after broker_subscriptions check.. broker_subs:{:?} ", + broker_subs + ); let subs = { + println!("@@@@NNA,,, in subs check with subs"); let mut br_subs = broker_subs.write().unwrap(); br_subs.get_mut(&event_name).cloned() }; - if let Some(subs) = subs { - for s in subs { - if let Some(resp_msg) = response.get_device_resp_msg() { + + if let Some(dev_resp_sub) = subs { + //let subc = subs; + for s in &dev_resp_sub.handlers { + if let Some(resp_msg) = + response.get_device_resp_msg(dev_resp_sub.clone().sub_id) + { + println!( + "@@NNA....after get_device_resp_msg() with resp_msg:{:?}", + resp_msg + ); mpsc_send_and_log(&s, resp_msg, "ThunderResponse").await; } } @@ -261,31 +294,60 @@ impl DeviceOperator for ThunderClient { params: request.params, callback: tx, }); + println!( + "@@@NNA---->in DeviceOperator::call req with msg{:?}", + message + ); self.send_message(message).await; + // match rx.await { + // Ok(response) => response, + // Err(_) => DeviceResponseMessage { + // message: Value::Null, + // sub_id: None, + // }, + // } match rx.await { - Ok(response) => response, + Ok(response) => { + println!( + "@@@NNA....thunderclient deviceoperator response received:{:?}", + response + ); + response + } Err(_) => DeviceResponseMessage { message: Value::Null, sub_id: None, }, } } else { - let (_tx, rx) = oneshot::channel::(); + let (tx, rx) = oneshot::channel::(); let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); - self.add_to_callback(&async_request); + self.add_to_callback(&async_request, tx); + println!( + "@@@NNA---->in DeviceOperator::call req with msg{:?}", + async_request + ); if let Some(async_client) = &self.thndr_asynclient { async_client.send(async_request).await; } + println!("@@@NNA----->after deviceoperator call send fn .."); match rx.await { - Ok(response) => response, + Ok(response) => { + println!("@@@NNA....deviceoperator response received:{:?}", response); + response + } Err(_) => DeviceResponseMessage { message: Value::Null, sub_id: None, }, } + // DeviceResponseMessage { + // message: Value::Null, + // sub_id: None, + // } } } @@ -305,16 +367,56 @@ impl DeviceOperator for ThunderClient { sub_id: request.sub_id, }; let msg = ThunderMessage::ThunderSubscribeMessage(message); + println!( + "@@@NNA---->in DeviceOperator::subscribe req with msg{:?}", + msg + ); self.send_message(msg).await; - rx.await.unwrap() + println!("****deviceoperator subscribe request waiting for response..."); + //rx.await.unwrap() + match rx.await { + Ok(response) => { + println!( + "@@@NNA....thunderclient deviceoperator subscription response received:{:?}", + response + ); + response + } + Err(_) => DeviceResponseMessage { + message: Value::Null, + sub_id: None, + }, + } } else if let Some(subscribe_request) = self.check_sub(&request, handler.clone()) { - let (_tx, rx) = oneshot::channel::(); - self.add_to_callback(&subscribe_request); - + let (tx, rx) = oneshot::channel::(); + self.add_to_callback(&subscribe_request, tx); + println!( + "@@@NNA---->in DeviceOperator::subscribe req with msg{:?}", + subscribe_request + ); if let Some(async_client) = &self.thndr_asynclient { async_client.send(subscribe_request).await; } - rx.await.unwrap() + println!("@@@NNA----> subscribe request waiting for response..."); + + match rx.await { + Ok(response) => { + println!( + "@@@NNA....deviceoperator subscription response received:{:?}", + response + ); + response + } + Err(_) => DeviceResponseMessage { + message: Value::Null, + sub_id: None, + }, + } + //rx.await.unwrap() + // DeviceResponseMessage { + // message: Value::Null, + // sub_id: None, + // } } else { DeviceResponseMessage { message: Value::Null, @@ -577,26 +679,55 @@ impl ThunderClient { None } - fn add_to_callback(&self, request: &ThunderAsyncRequest) { + fn add_to_callback( + &self, + request: &ThunderAsyncRequest, + dev_resp_callback: Sender, + ) { let mut callbacks = self.broker_callbacks.as_ref().unwrap().write().unwrap(); - callbacks.insert(request.id, None); + callbacks.insert(request.id, Some(dev_resp_callback)); } + // fn add_to_brokersubmap( + // &self, + // request: &ThunderAsyncRequest, + // dev_resp_callback: Sender, + // ) { + // let mut brokersubs = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); + // brokersubs.insert(request, Some(dev_resp_callback)); + // } + // if already subscibed updated handlers fn check_sub( &self, request: &DeviceSubscribeRequest, handler: MpscSender, ) -> Option { + println!("@@@NNA----> in check_sub function"); let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); - let key = format!("{}.{}", request.module, request.event_name); + let key = format!("client.events.{}", request.event_name); if let Some(subs) = broker_subscriptions.get_mut(&key) { - subs.push(handler); + println!( + "@@@NNA----> Adding handler to existing subscription for key: {}", + key + ); + + subs.handlers.push(handler); None } else { let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Subscribe(request.clone())); - broker_subscriptions.insert(key, vec![handler]); + println!( + "@@@NNA----> async_request: {:?}, broker_subscriptions: {:?}", + async_request, broker_subscriptions + ); + + let dev_resp_sub = DeviceResponseSubscription { + sub_id: request.clone().sub_id, + handlers: vec![handler], + }; + + broker_subscriptions.insert(key, dev_resp_sub); Some(async_request) } } @@ -812,10 +943,12 @@ impl ThunderClientBuilder { use_thunderbroker: false, }) } else { - let (sender, tr) = mpsc::channel(10); - let callback = BrokerCallback { sender }; + let (resp_tx, resp_rx) = mpsc::channel(10); + let callback = BrokerCallback { sender: resp_tx }; let (broker_tx, broker_rx) = mpsc::channel(10); - let client = ThunderAsyncClient::new(callback, broker_tx); + let broker_sender = BrokerSender { sender: broker_tx }; + let client = ThunderAsyncClient::new(callback, broker_sender); + let thunder_client = ThunderClient { sender: None, pooled_sender: None, @@ -831,10 +964,9 @@ impl ThunderClientBuilder { ThunderClientManager::manage( thunder_client.clone(), broker_rx, - tr, + resp_rx, url.unwrap().to_string(), ); - Ok(thunder_client) } } From ab0b10a4cf87dd97e2c115aaed520e9e90bf50a9 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 24 Dec 2024 12:27:53 +0530 Subject: [PATCH 19/51] fix: fixed the clippy errors --- device/thunder_ripple_sdk/src/client/thunder_async_client.rs | 4 ++-- device/thunder_ripple_sdk/src/client/thunder_client.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 86a5fe9c0..1f2a7a285 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -108,7 +108,7 @@ impl ThunderAsyncResponse { device_response_msg = Some(DeviceResponseMessage::new(res.clone(), sub_id)); } else if let Some(er) = &json_resp.error { device_response_msg = Some(DeviceResponseMessage::new(er.clone(), sub_id)); - } else if !json_resp.clone().method.is_none() { + } else if json_resp.clone().method.is_some() { if let Some(params) = &json_resp.params { let dev_resp = serde_json::to_value(params).unwrap(); device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); @@ -280,7 +280,7 @@ impl ThunderAsyncClient { json!({ "jsonrpc": "2.0", "id": id, - "method": format!("{}.register", callsign), + "method": format!("{}.register", callsign), "params": json!({ "event": method, "id": "client.events" diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index b63d3b06d..a7b3fda21 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -144,7 +144,7 @@ impl ThunderClientManager { "@@NNA....after get_device_resp_msg() with resp_msg:{:?}", resp_msg ); - mpsc_send_and_log(&s, resp_msg, "ThunderResponse").await; + mpsc_send_and_log(s, resp_msg, "ThunderResponse").await; } } } From 0ec2df85cdf767c5907ed6349c5a07cc3345178e Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 2 Jan 2025 20:25:46 +0530 Subject: [PATCH 20/51] fix: clippy warnings fixed, unit tests added thunder_async_client --- .../src/client/thunder_async_client.rs | 203 +++++++++++++++++- .../src/client/thunder_client.rs | 11 +- ...rs => thunderbroker_plugins_status_mgr.rs} | 0 device/thunder_ripple_sdk/src/lib.rs | 2 +- 4 files changed, 204 insertions(+), 12 deletions(-) rename device/thunder_ripple_sdk/src/client/{thunder_plugins_status_mgr.rs => thunderbroker_plugins_status_mgr.rs} (100%) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 1f2a7a285..e1964f08a 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -33,7 +33,7 @@ use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; use crate::utils::get_next_id; -use super::thunder_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; +use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; #[derive(Clone, Debug)] pub struct ThunderAsyncClient { @@ -414,3 +414,204 @@ impl ThunderAsyncClient { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::client::thunder_client::ThunderClient; + //use crate::client::thunder_client_pool::tests::Uuid; + use ripple_sdk::api::device::device_operator::{DeviceCallRequest, DeviceChannelRequest}; + use ripple_sdk::api::gateway::rpc_gateway_api::JsonRpcApiResponse; + //use ripple_sdk::async_channel::Recv; + use ripple_sdk::utils::error::RippleError; + use ripple_sdk::uuid::Uuid; + use std::collections::HashMap; + use std::sync::{Arc, RwLock}; + use tokio::sync::mpsc; + + #[tokio::test] + async fn test_thunder_async_request_new() { + let callrequest = DeviceCallRequest { + method: "org.rdk.System.1.getSerialNumber".to_string(), + params: None, + }; + + let request = DeviceChannelRequest::Call(callrequest); + let _async_request = ThunderAsyncRequest::new(request.clone()); + assert_eq!( + _async_request.request.get_callsign_method(), + request.get_callsign_method() + ); + } + + #[tokio::test] + async fn test_thunder_async_response_new_response() { + let response = JsonRpcApiResponse { + jsonrpc: "2.0".to_string(), + id: Some(6), + result: Some(json!({"key": "value"})), + error: None, + method: None, + params: None, + }; + + let _async_response = ThunderAsyncResponse::new_response(response.clone()); + assert_eq!(_async_response.result.unwrap().result, response.result); + } + + #[tokio::test] + async fn test_thunder_async_response_new_error() { + let error = RippleError::ServiceError; + let async_response = ThunderAsyncResponse::new_error(1, error.clone()); + assert_eq!(async_response.id, Some(1)); + assert_eq!(async_response.result.unwrap_err(), error); + } + + #[tokio::test] + async fn test_thunder_async_response_get_event() { + let response = JsonRpcApiResponse { + jsonrpc: "2.0".to_string(), + id: Some(6), + result: Some(json!({"key": "value"})), + error: None, + method: Some("event_1".to_string()), + params: None, + }; + let async_response = ThunderAsyncResponse::new_response(response); + assert_eq!(async_response.get_event(), Some("event_1".to_string())); + } + + #[tokio::test] + async fn test_thunder_async_response_get_id() { + let response = JsonRpcApiResponse { + jsonrpc: "2.0".to_string(), + id: Some(42), + result: Some(json!({"key": "value"})), + error: None, + method: Some("event_1".to_string()), + params: None, + }; + let async_response = ThunderAsyncResponse::new_response(response); + assert_eq!(async_response.get_id(), Some(42)); + } + + #[tokio::test] + async fn test_thunder_async_response_get_device_resp_msg() { + let response = JsonRpcApiResponse { + jsonrpc: "2.0".to_string(), + id: Some(6), + result: Some(json!({"key": "value"})), + error: None, + method: Some("event_1".to_string()), + params: None, + }; + let async_response = ThunderAsyncResponse::new_response(response); + let device_resp_msg = async_response.get_device_resp_msg(None); + assert_eq!(device_resp_msg.unwrap().message, json!({"key": "value"})); + } + + #[tokio::test] + async fn test_thunder_async_client_get_id_from_result() { + let response = json!({"id": 42}).to_string(); + let id = ThunderAsyncClient::get_id_from_result(response.as_bytes()); + assert_ne!(id, Some(42)); + } + + #[tokio::test] + async fn test_thunder_async_client_prepare_request() { + let (resp_tx, _resp_rx) = mpsc::channel(10); + let callback = BrokerCallback { sender: resp_tx }; + let (broker_tx, _broker_rx) = mpsc::channel(10); + let broker_sender = BrokerSender { sender: broker_tx }; + let client = ThunderAsyncClient::new(callback, broker_sender); + + let callrequest = DeviceCallRequest { + method: "org.rdk.System.1.getSerialNumber".to_string(), + params: None, + }; + + let request = DeviceChannelRequest::Call(callrequest); + let async_request = ThunderAsyncRequest::new(request); + let result = client.prepare_request(&async_request); + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_thunder_async_client_send() { + let (resp_tx, _resp_rx) = mpsc::channel(10); + let callback = BrokerCallback { sender: resp_tx }; + let (broker_tx, mut broker_rx) = mpsc::channel(10); + let broker_sender = BrokerSender { sender: broker_tx }; + let client = ThunderAsyncClient::new(callback, broker_sender); + + let callrequest = DeviceCallRequest { + method: "org.rdk.System.1.getSerialNumber".to_string(), + params: None, + }; + + let request = DeviceChannelRequest::Call(callrequest); + let async_request = ThunderAsyncRequest::new(request); + client.send(async_request.clone()).await; + let received = broker_rx.recv().await; + assert_eq!(received.unwrap().id, async_request.id); + } + + #[tokio::test] + async fn test_thunder_async_client_handle_jsonrpc_response() { + let (resp_tx, mut resp_rx) = mpsc::channel(10); + let callback = BrokerCallback { sender: resp_tx }; + let response = JsonRpcApiResponse { + jsonrpc: "2.0".to_string(), + id: Some(6), + result: Some(json!({"key": "value"})), + error: None, + method: Some("event_1".to_string()), + params: None, + }; + let response_bytes = serde_json::to_vec(&response).unwrap(); + ThunderAsyncClient::handle_jsonrpc_response(&response_bytes, callback).await; + let received = resp_rx.recv().await; + assert_eq!( + received.unwrap().result.unwrap().result, + Some(json!({"key": "value"})) + ); + } + + #[tokio::test] + async fn test_thunder_async_client_start() { + let (resp_tx, mut resp_rx) = mpsc::channel(10); + let callback = BrokerCallback { sender: resp_tx }; + let (broker_tx, _broker_rx) = mpsc::channel(10); + let broker_sender = BrokerSender { sender: broker_tx }; + let client = ThunderAsyncClient::new(callback.clone(), broker_sender); + + let _thunder_client = ThunderClient { + sender: None, + pooled_sender: None, + id: Uuid::new_v4(), + plugin_manager_tx: None, + subscriptions: None, + thndr_asynclient: Some(client), + broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), + broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), + use_thunderbroker: true, + }; + + let response = json!({ + "jsonrpc": "2.0", + "result": { + "key": "value" + } + }); + + ThunderAsyncClient::handle_jsonrpc_response(response.to_string().as_bytes(), callback) + .await; + let received = resp_rx.recv().await; + assert!(received.is_some()); + let async_response = received.unwrap(); + assert_eq!( + async_response.result.unwrap().result, + Some(json!({"key": "value"})) + ); + } +} diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index a7b3fda21..8b3c3dc9e 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -58,7 +58,7 @@ use url::Url; use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; use super::thunder_client_pool::ThunderPoolCommand; -use super::thunder_plugins_status_mgr::{BrokerCallback, BrokerSender}; +use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender}; use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, @@ -688,15 +688,6 @@ impl ThunderClient { callbacks.insert(request.id, Some(dev_resp_callback)); } - // fn add_to_brokersubmap( - // &self, - // request: &ThunderAsyncRequest, - // dev_resp_callback: Sender, - // ) { - // let mut brokersubs = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); - // brokersubs.insert(request, Some(dev_resp_callback)); - // } - // if already subscibed updated handlers fn check_sub( &self, diff --git a/device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs similarity index 100% rename from device/thunder_ripple_sdk/src/client/thunder_plugins_status_mgr.rs rename to device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index 285bc4212..1c93ac43f 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -22,7 +22,7 @@ pub mod client { pub mod thunder_client; pub mod thunder_client_pool; pub mod thunder_plugin; - pub mod thunder_plugins_status_mgr; + pub mod thunderbroker_plugins_status_mgr; } pub mod bootstrap { From 3b4805211b6428e39073e2c32b18c4381ee16426 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 7 Jan 2025 17:57:39 +0530 Subject: [PATCH 21/51] fix: fixed review comments --- core/main/src/broker/broker_utils.rs | 6 +- core/main/src/broker/endpoint_broker.rs | 19 +- .../thunder/thunder_plugins_status_mgr.rs | 11 +- .../src/broker/thunder/user_data_migrator.rs | 14 +- core/sdk/src/api/device/device_operator.rs | 61 ++--- core/sdk/src/utils/rpc_utils.rs | 23 +- .../src/bootstrap/boot_thunder.rs | 37 +-- .../src/bootstrap/get_config_step.rs | 2 +- .../src/bootstrap/setup_thunder_pool_step.rs | 24 +- .../src/client/thunder_async_client.rs | 252 +++++++----------- .../src/client/thunder_client.rs | 208 +++------------ .../src/client/thunder_client_pool.rs | 6 +- .../thunderbroker_plugins_status_mgr.rs | 7 +- .../src/processors/thunder_package_manager.rs | 4 +- .../src/tests/mock_thunder_controller.rs | 2 +- .../thunder_ripple_sdk/src/thunder_state.rs | 2 +- device/thunder_ripple_sdk/src/utils.rs | 12 +- 17 files changed, 250 insertions(+), 440 deletions(-) diff --git a/core/main/src/broker/broker_utils.rs b/core/main/src/broker/broker_utils.rs index 49aa892f3..911122770 100644 --- a/core/main/src/broker/broker_utils.rs +++ b/core/main/src/broker/broker_utils.rs @@ -47,12 +47,14 @@ impl BrokerUtils { }; let url = url::Url::parse(&url_path).unwrap(); let port = extract_tcp_port(endpoint); + let tcp_port = port.unwrap(); + info!("Url host str {}", url.host_str().unwrap()); let mut index = 0; loop { // Try connecting to the tcp port first - if let Ok(v) = TcpStream::connect(&port).await { + if let Ok(v) = TcpStream::connect(&tcp_port).await { // Setup handshake for websocket with the tcp port // Some WS servers lock on to the Port but not setup handshake till they are fully setup if let Ok((stream, _)) = client_async(url_path.clone(), v).await { @@ -62,7 +64,7 @@ impl BrokerUtils { if (index % 10).eq(&0) { error!( "Broker with {} failed with retry for last {} secs in {}", - url_path, index, port + url_path, index, tcp_port ); } index += 1; diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index cc0e0820c..ecdaa7e33 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -30,16 +30,13 @@ use ripple_sdk::{ self, sync::mpsc::{self, Receiver, Sender}, }, - utils::error::RippleError, + utils::{error::RippleError, rpc_utils::get_next_id}, }; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::{ collections::HashMap, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, RwLock, - }, + sync::{Arc, RwLock}, }; use crate::{ @@ -204,7 +201,7 @@ impl Default for BrokerCallback { } } -static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); +// static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); impl BrokerCallback { pub async fn send_json_rpc_api_response(&self, response: JsonRpcApiResponse) { @@ -410,10 +407,10 @@ impl EndpointBrokerState { } } - pub fn get_next_id() -> u64 { - ATOMIC_ID.fetch_add(1, Ordering::Relaxed); - ATOMIC_ID.load(Ordering::Relaxed) - } + // pub fn get_next_id() -> u64 { + // ATOMIC_ID.fetch_add(1, Ordering::Relaxed); + // ATOMIC_ID.load(Ordering::Relaxed) + // } fn update_request( &self, @@ -422,7 +419,7 @@ impl EndpointBrokerState { extn_message: Option, workflow_callback: Option, ) -> (u64, BrokerRequest) { - let id = Self::get_next_id(); + let id = get_next_id(); let mut rpc_request_c = rpc_request.clone(); { let mut request_map = self.request_map.write().unwrap(); diff --git a/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs b/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs index b11274278..946d8ccbb 100644 --- a/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs +++ b/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs @@ -28,9 +28,8 @@ use ripple_sdk::{ use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::broker::endpoint_broker::{ - BrokerCallback, BrokerRequest, BrokerSender, EndpointBrokerState, -}; +use crate::broker::endpoint_broker::{BrokerCallback, BrokerRequest, BrokerSender}; +use ripple_sdk::utils::rpc_utils::get_next_id; // defautl timeout for plugin activation in seconds const DEFAULT_PLUGIN_ACTIVATION_TIMEOUT: i64 = 8; @@ -229,7 +228,7 @@ impl StatusManager { } pub fn generate_plugin_activation_request(&self, plugin_name: String) -> String { - let id = EndpointBrokerState::get_next_id(); + let id = get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ @@ -247,7 +246,7 @@ impl StatusManager { } pub fn generate_plugin_status_request(&self, plugin_name: String) -> String { - let id = EndpointBrokerState::get_next_id(); + let id = get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ @@ -262,7 +261,7 @@ impl StatusManager { } pub fn generate_state_change_subscribe_request(&self) -> String { - let id = EndpointBrokerState::get_next_id(); + let id = get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ diff --git a/core/main/src/broker/thunder/user_data_migrator.rs b/core/main/src/broker/thunder/user_data_migrator.rs index 59b13bb2d..1c042814c 100644 --- a/core/main/src/broker/thunder/user_data_migrator.rs +++ b/core/main/src/broker/thunder/user_data_migrator.rs @@ -35,15 +35,13 @@ use ripple_sdk::{ }, time::{timeout, Duration}, }, - utils::error::RippleError, + utils::{error::RippleError, rpc_utils::get_next_id}, }; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use crate::broker::endpoint_broker::{ - self, BrokerCallback, BrokerOutput, BrokerRequest, EndpointBrokerState, -}; +use crate::broker::endpoint_broker::{self, BrokerCallback, BrokerOutput, BrokerRequest}; use crate::broker::rules_engine::{Rule, RuleTransformType}; use futures::stream::SplitSink; @@ -282,7 +280,7 @@ impl UserDataMigrator { broker: &ThunderBroker, ws_tx: Arc, Message>>>, ) -> Result { - let request_id = EndpointBrokerState::get_next_id(); + let request_id = get_next_id(); let call_sign = "org.rdk.PersistentStore.1.".to_owned(); // Register custom callback to handle the response @@ -369,7 +367,7 @@ impl UserDataMigrator { ws_tx: Arc, Message>>>, params_json: &Value, ) -> Result<(), UserDataMigratorError> { - let request_id = EndpointBrokerState::get_next_id(); + let request_id = get_next_id(); let call_sign = "org.rdk.PersistentStore.1.".to_owned(); // Register custom callback to handle the response @@ -436,7 +434,7 @@ impl UserDataMigrator { ws_tx: Arc, Message>>>, request: &BrokerRequest, ) -> Result { - let request_id = EndpointBrokerState::get_next_id(); + let request_id = get_next_id(); // Register custom callback to handle the response broker @@ -528,7 +526,7 @@ impl UserDataMigrator { } }; - let request_id = EndpointBrokerState::get_next_id(); + let request_id = get_next_id(); // Register custom callback to handle the response broker diff --git a/core/sdk/src/api/device/device_operator.rs b/core/sdk/src/api/device/device_operator.rs index 5fd1fbfd8..10b2e9e29 100644 --- a/core/sdk/src/api/device/device_operator.rs +++ b/core/sdk/src/api/device/device_operator.rs @@ -15,7 +15,9 @@ // SPDX-License-Identifier: Apache-2.0 // +use crate::api::gateway::rpc_gateway_api::JsonRpcApiResponse; use async_trait::async_trait; +use log::error; use serde::{Deserialize, Serialize}; use serde_json::Value; use tokio::sync::mpsc; @@ -36,41 +38,6 @@ pub trait DeviceOperator: Clone { async fn unsubscribe(&self, request: DeviceUnsubscribeRequest); } - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum DeviceChannelRequest { - Call(DeviceCallRequest), - Subscribe(DeviceSubscribeRequest), - Unsubscribe(DeviceUnsubscribeRequest), -} - -impl DeviceChannelRequest { - pub fn get_callsign_method(&self) -> (String, String) { - match self { - DeviceChannelRequest::Call(c) => { - let mut collection: Vec<&str> = c.method.split('.').collect(); - let method = collection.pop().unwrap_or_default(); - let callsign = collection.join("."); - (callsign, method.into()) - } - DeviceChannelRequest::Subscribe(s) => (s.module.clone(), s.event_name.clone()), - DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), - } - } - - pub fn is_subscription(&self) -> bool { - !matches!(self, DeviceChannelRequest::Call(_)) - } - - pub fn is_unsubscribe(&self) -> Option { - if let DeviceChannelRequest::Unsubscribe(u) = self { - Some(u.clone()) - } else { - None - } - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeviceCallRequest { pub method: String, @@ -147,12 +114,26 @@ impl DeviceResponseMessage { pub fn new(message: Value, sub_id: Option) -> DeviceResponseMessage { DeviceResponseMessage { message, sub_id } } -} -#[derive(Debug, Clone)] -pub struct DeviceResponseSubscription { - pub sub_id: Option, - pub handlers: Vec>, + pub fn create( + json_resp: &JsonRpcApiResponse, + sub_id: Option, + ) -> Option { + let mut device_response_msg = None; + if let Some(res) = &json_resp.result { + device_response_msg = Some(DeviceResponseMessage::new(res.clone(), sub_id)); + } else if let Some(er) = &json_resp.error { + device_response_msg = Some(DeviceResponseMessage::new(er.clone(), sub_id)); + } else if json_resp.clone().method.is_some() { + if let Some(params) = &json_resp.params { + let dev_resp = serde_json::to_value(params).unwrap(); + device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); + } + } else { + error!("deviceresponse msg extraction failed."); + } + device_response_msg + } } #[cfg(test)] diff --git a/core/sdk/src/utils/rpc_utils.rs b/core/sdk/src/utils/rpc_utils.rs index 9d2d79bb4..31c91d39a 100644 --- a/core/sdk/src/utils/rpc_utils.rs +++ b/core/sdk/src/utils/rpc_utils.rs @@ -16,17 +16,34 @@ // use jsonrpsee::core::Error; +use std::sync::atomic::{AtomicU64, Ordering}; + +static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); + +pub fn get_next_id() -> u64 { + ATOMIC_ID.fetch_add(1, Ordering::Relaxed); + ATOMIC_ID.load(Ordering::Relaxed) +} pub fn rpc_err(msg: impl Into) -> Error { Error::Custom(msg.into()) } -pub fn extract_tcp_port(url: &str) -> String { +pub fn extract_tcp_port(url: &str) -> Result { let url_split: Vec<&str> = url.split("://").collect(); if let Some(domain) = url_split.get(1) { let domain_split: Vec<&str> = domain.split('/').collect(); - domain_split.first().unwrap().to_string() + Ok(domain_split.first().unwrap().to_string()) } else { - url.to_owned() + Err(Error::Custom("Invalid URL format".to_string())) } } +// pub fn extract_tcp_port(url: &str) -> String { +// let url_split: Vec<&str> = url.split("://").collect(); +// if let Some(domain) = url_split.get(1) { +// let domain_split: Vec<&str> = domain.split('/').collect(); +// domain_split.first().unwrap().to_string() +// } else { +// url.to_owned() +// } +// } diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index ab5891659..a52837844 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -22,7 +22,6 @@ use crate::{ use ripple_sdk::{ extn::client::extn_client::ExtnClient, log::{debug, error, info, warn}, - serde_json::{self, Error}, }; use super::{get_config_step::ThunderGetConfigStep, setup_thunder_pool_step::ThunderPoolStep}; @@ -51,7 +50,7 @@ pub async fn boot_thunder( ext_client: ExtnClient, plugin_param: ThunderPluginBootParam, ) -> Option { - info!("Booting thunder"); + info!("Booting thunder initiated"); //by default enabling the thunderBroker if ext_client.get_bool_config("use_with_thunder_broker") { info!("Using thunder broker"); @@ -62,22 +61,25 @@ pub async fn boot_thunder( if let Ok(message) = extn_message_response { if let Some(ExtnResponse::Value(v)) = message.payload.extract() { - let tp_res: Result = serde_json::from_value(v); - if let Ok(thunder_parameters) = tp_res { - if let Ok(gtway_url) = url::Url::parse(&thunder_parameters.gateway) { - debug!("Got url from device manifest"); - gateway_url = gtway_url - } else { + match serde_json::from_value::(v) { + Ok(thunder_parameters) => match url::Url::parse(&thunder_parameters.gateway) { + Ok(gtway_url) => { + debug!("Got url:{} from device manifest", gtway_url); + gateway_url = gtway_url; + } + Err(_) => { + warn!( + "Could not parse thunder gateway '{}', using default {}", + thunder_parameters.gateway, GATEWAY_DEFAULT + ); + } + }, + Err(_) => { warn!( - "Could not parse thunder gateway '{}', using default {}", - thunder_parameters.gateway, GATEWAY_DEFAULT + "Could not read thunder platform parameters, using default {}", + GATEWAY_DEFAULT ); } - } else { - warn!( - "Could not read thunder platform parameters, using default {}", - GATEWAY_DEFAULT - ); } if let Ok(host_override) = std::env::var("DEVICE_HOST") { gateway_url.set_host(Some(&host_override)).ok(); @@ -86,13 +88,14 @@ pub async fn boot_thunder( } if let Ok(thndr_client) = - ThunderClientBuilder::get_client(Some(gateway_url), None, None, None, None, true).await + ThunderClientBuilder::get_client(gateway_url.clone(), None, None, None, None, true) + .await { let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); let thndr_boot_statecfg = ThunderBootstrapStateWithConfig { extn_client: ext_client, - url: None, + url: gateway_url, pool_size: None, plugin_param: None, thunder_connection_state: None, diff --git a/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs b/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs index 4a940333c..d0e28207d 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/get_config_step.rs @@ -92,7 +92,7 @@ impl ThunderGetConfigStep { } return Ok(ThunderBootstrapStateWithConfig { extn_client: state, - url: Some(gateway_url), + url: gateway_url, pool_size: Some(pool_size), plugin_param: Some(expected_plugins), thunder_connection_state: Some(Arc::new(ThunderConnectionState::new())), diff --git a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs index 247c62953..cb55bad11 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs @@ -40,21 +40,19 @@ impl ThunderPoolStep { pub async fn setup( state: ThunderBootstrapStateWithConfig, ) -> Result { - let pool_size = state.pool_size; let url = state.url.clone(); let thunder_connection_state = state.thunder_connection_state.clone(); - if pool_size < Some(2) { - warn!("Pool size of 1 is not recommended, there will be no dedicated connection for Controller events"); - return Err(RippleError::BootstrapError); - } + let pool_size = match state.pool_size { + Some(s) => s, + None => { + warn!("Pool size of 1 is not recommended, there will be no dedicated connection for Controller events"); + return Err(RippleError::BootstrapError); + } + }; + let controller_pool = ripple_sdk::tokio::time::timeout( Duration::from_secs(10), - ThunderClientPool::start( - url.clone().unwrap(), - None, - thunder_connection_state.clone(), - 1, - ), + ThunderClientPool::start(url.clone(), None, thunder_connection_state.clone(), 1), ) .await; @@ -103,10 +101,10 @@ impl ThunderPoolStep { } let client = ThunderClientPool::start( - url.clone().unwrap(), + url.clone(), Some(plugin_manager_tx), thunder_connection_state.clone(), - pool_size.unwrap() - 1, + pool_size - 1, ) .await; diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index e1964f08a..e6cfb6632 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -17,23 +17,67 @@ use std::time::Duration; +use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; use ripple_sdk::api::device::device_operator::DeviceResponseMessage; use ripple_sdk::{ api::{ - device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, + device::device_operator::{ + DeviceCallRequest, DeviceSubscribeRequest, DeviceUnsubscribeRequest, + }, + gateway::rpc_gateway_api::JsonRpcApiResponse, }, log::{debug, error, info}, tokio::{self, net::TcpStream, sync::mpsc::Receiver}, - utils::{error::RippleError, rpc_utils::extract_tcp_port}, + utils::{ + error::RippleError, + rpc_utils::{extract_tcp_port, get_next_id}, + }, }; +use serde::{Deserialize, Serialize}; use serde_json::json; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; -use crate::utils::get_next_id; +#[derive(Debug, Clone)] +pub struct DeviceResponseSubscription { + pub sub_id: Option, + pub handlers: Vec>, +} -use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum DeviceChannelRequest { + Call(DeviceCallRequest), + Subscribe(DeviceSubscribeRequest), + Unsubscribe(DeviceUnsubscribeRequest), +} + +impl DeviceChannelRequest { + pub fn get_callsign_method(&self) -> (String, String) { + match self { + DeviceChannelRequest::Call(c) => { + let mut collection: Vec<&str> = c.method.split('.').collect(); + let method = collection.pop().unwrap_or_default(); + let callsign = collection.join("."); + (callsign, method.into()) + } + DeviceChannelRequest::Subscribe(s) => (s.module.clone(), s.event_name.clone()), + DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), + } + } + + pub fn is_subscription(&self) -> bool { + !matches!(self, DeviceChannelRequest::Call(_)) + } + + pub fn is_unsubscribe(&self) -> Option { + if let DeviceChannelRequest::Unsubscribe(u) = self { + Some(u.clone()) + } else { + None + } + } +} #[derive(Clone, Debug)] pub struct ThunderAsyncClient { @@ -78,7 +122,7 @@ impl ThunderAsyncResponse { } } - pub fn get_event(&self) -> Option { + pub fn get_method(&self) -> Option { if let Ok(e) = &self.result { return e.method.clone(); } @@ -93,46 +137,20 @@ impl ThunderAsyncResponse { } pub fn get_device_resp_msg(&self, sub_id: Option) -> Option { - println!("@@NNA...get_device_resp_msg res:{:?}", self.result); let json_resp = match &self.result { - Ok(json_resp_res) => { - println!("@@NNA...get_device_resp_msg resp::{:?}", json_resp_res); - json_resp_res - } + Ok(json_resp_res) => json_resp_res, _ => return None, }; - - let mut device_response_msg = None; - - if let Some(res) = &json_resp.result { - device_response_msg = Some(DeviceResponseMessage::new(res.clone(), sub_id)); - } else if let Some(er) = &json_resp.error { - device_response_msg = Some(DeviceResponseMessage::new(er.clone(), sub_id)); - } else if json_resp.clone().method.is_some() { - if let Some(params) = &json_resp.params { - let dev_resp = serde_json::to_value(params).unwrap(); - device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); - } - } else { - error!("deviceresponse msg extraction failed."); - } - println!("@@NNA...device_response_msg: {:?}", device_response_msg); - device_response_msg + DeviceResponseMessage::create(json_resp, sub_id) } } impl ThunderAsyncClient { - fn get_id_from_result(result: &[u8]) -> Option { - serde_json::from_slice::(result) - .ok() - .and_then(|data| data.id) - } - pub fn get_sender(&self) -> BrokerSender { self.sender.clone() } - pub fn get_thndrasync_callback(&self) -> BrokerCallback { + pub fn get_callback(&self) -> BrokerCallback { self.callback.clone() } async fn create_ws( @@ -142,15 +160,13 @@ impl ThunderAsyncClient { SplitStream>, ) { info!("Broker Endpoint url {}", endpoint); - - let url = url::Url::parse(endpoint).unwrap(); let port = extract_tcp_port(endpoint); - info!("Url host str {}", url.host_str().unwrap()); + let tcp_port = port.unwrap(); let mut index = 0; loop { // Try connecting to the tcp port first - if let Ok(v) = TcpStream::connect(&port).await { + if let Ok(v) = TcpStream::connect(&tcp_port).await { // Setup handshake for websocket with the tcp port // Some WS servers lock on to the Port but not setup handshake till they are fully setup if let Ok((stream, _)) = client_async(endpoint, v).await { @@ -160,7 +176,7 @@ impl ThunderAsyncClient { if (index % 10).eq(&0) { error!( "Broker with {} failed with retry for last {} secs in {}", - endpoint, index, port + endpoint, index, tcp_port ); } index += 1; @@ -169,31 +185,23 @@ impl ThunderAsyncClient { } fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result, RippleError> { - println!("@@@NNA-----> in start prepare request id :{}", request.id); let mut requests = Vec::new(); let id: u64 = request.id; let (callsign, method) = request.request.get_callsign_method(); - println!( - "@@@NNA-----> in prepare request callsign :{}, method :{}", - callsign, method - ); + + // Check if the method is empty and return an error if it is if method.is_empty() { return Err(RippleError::InvalidInput); } - // check if the plugin is activated. + + // Check the status of the plugin using the status manager let status = match self.status_manager.get_status(callsign.clone()) { - Some(v) => { - println!( - "@@@NNA....status_manager.get_status returned some value. v:{:?} ", - v - ); - v.clone() - } + Some(v) => v.clone(), None => { - println!("@@@NNA....status_manager.get_status return none."); + // If the plugin status is not available, add the request to the pending list self.status_manager .add_broker_request_to_pending_list(callsign.clone(), request.clone()); - // PluginState is not available with StateManager, create an internal thunder request to activate the plugin + // Generate a request to check the plugin status and add it to the requests list let request = self .status_manager .generate_plugin_status_request(callsign.clone()); @@ -201,94 +209,65 @@ impl ThunderAsyncClient { return Ok(requests); } }; - println!( - "@@@NNA-----> in prepare request ThunderPluginState :{:?} ", - status - ); + // If the plugin is missing, return a service error if status.state.is_missing() { error!("Plugin {} is missing", callsign); return Err(RippleError::ServiceError); } + // If the plugin is activating, return a service not ready error if status.state.is_activating() { info!("Plugin {} is activating", callsign); return Err(RippleError::ServiceNotReady); } + // If the plugin is not activated, add the request to the pending list and generate an activation request if !status.state.is_activated() { - println!("@@@NNA....plugin not activated yet..."); - // add the broker request to pending list self.status_manager .add_broker_request_to_pending_list(callsign.clone(), request.clone()); - // create an internal thunder request to activate the plugin let request = self .status_manager .generate_plugin_activation_request(callsign.clone()); requests.push(request.to_string()); return Ok(requests); - } else { - println!("@@@NNA....plugin is activated Now...&&&&&..."); } - println!( - "@@@NNA....after plugin activation devicechannelrequest : {:?} ", - request.request - ); - + // Generate the appropriate JSON-RPC request based on the type of DeviceChannelRequest match &request.request { - DeviceChannelRequest::Call(c) => { - println!( - "@@@NNA-----> in DeviceChannelRequest::Call request id :{}", - request.id - ); - // Simple request and response handling - requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": c.method, - "params": c.params - }) - .to_string(), - ) - } - DeviceChannelRequest::Unsubscribe(_) => { - println!( - "@@@NNA-----> in DeviceChannelRequest::Unsubscribe request id :{}", - request.id - ); - requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.unregister", callsign), - "params": { - "event": method, - "id": "client.events" - } - }) - .to_string(), - ) - } - DeviceChannelRequest::Subscribe(_) => { - println!( - "@@@NNA-----> in DeviceChannelRequest::Subscribe request id :{}", - request.id - ); - requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.register", callsign), - "params": json!({ - "event": method, - "id": "client.events" - }) + DeviceChannelRequest::Call(c) => requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": c.method, + "params": c.params + }) + .to_string(), + ), + DeviceChannelRequest::Unsubscribe(_) => requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.unregister", callsign), + "params": { + "event": method, + "id": "client.events" + } + }) + .to_string(), + ), + DeviceChannelRequest::Subscribe(_) => requests.push( + json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.register", callsign), + "params": json!({ + "event": method, + "id": "client.events" }) - .to_string(), - ) - } + }) + .to_string(), + ), } Ok(requests) } @@ -327,20 +306,14 @@ impl ThunderAsyncClient { loop { tokio::select! { Some(value) = &mut read => { - debug!("@@@NNA...Got response in thunder async client start"); match value { Ok(v) => { - println!("@@@NNA----> msg v: {:?}",v); if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - println!("@@@NNA----> msg t: {:?}",t); if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { - debug!("@@@NNA---->Got response in thunder async client start before handle_controller_response. sender:{:?}, callback:{:?}",client_c.get_sender(), callback.clone() ); client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; - debug!("@@@NNA---->after step client_c.status_manager.handle_controller_response"); } else { - let id = Self::get_id_from_result(t.as_bytes()); - println!("@@@NNA.... jsn response id:{:?}, callback:{:?}", id, callback.clone()); + //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose // send the incoming text without context back to the sender Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await } @@ -355,13 +328,11 @@ impl ThunderAsyncClient { }, Some(request) = tr.recv() => { debug!("Got request from receiver for broker {:?}", request); - debug!("Got request from receiver for broker for method{:?}", request.request.get_callsign_method()); + // here prepare_request will check the plugin status and add json rpc format match client_c.prepare_request(&request) { Ok(updated_request) => { debug!("Sending request to broker {:?}", updated_request); for r in updated_request { - println!("@@@NNA----> we r at the feed, flush operations block...."); - println!("@@@NNA----> r :{}", r); let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; let _flush = ws_tx.flush().await; } @@ -376,9 +347,7 @@ impl ThunderAsyncClient { error!("error preparing request {:?}", e) } } - println!("@@@NNA----> before callback_for_sender send with response: {:?}", response); callback_for_sender.send(response).await; - println!("@@@NNA----> after callback_for_sender send "); } } } @@ -391,15 +360,7 @@ impl ThunderAsyncClient { /// Default handler method for the broker to remove the context and send it back to the /// client for consumption async fn handle_jsonrpc_response(result: &[u8], callback: BrokerCallback) { - debug!( - "@@@NNA...in handle_jsonrpc_response with callback: {:?}, result:{:?}", - callback, result - ); if let Ok(message) = serde_json::from_slice::(result) { - debug!( - "@@@NNA...in handle_jsonrpc_response msg:{:?} to callback:{:?}", - message, callback - ); callback .send(ThunderAsyncResponse::new_response(message)) .await @@ -420,7 +381,7 @@ mod tests { use super::*; use crate::client::thunder_client::ThunderClient; //use crate::client::thunder_client_pool::tests::Uuid; - use ripple_sdk::api::device::device_operator::{DeviceCallRequest, DeviceChannelRequest}; + use ripple_sdk::api::device::device_operator::DeviceCallRequest; use ripple_sdk::api::gateway::rpc_gateway_api::JsonRpcApiResponse; //use ripple_sdk::async_channel::Recv; use ripple_sdk::utils::error::RippleError; @@ -478,7 +439,7 @@ mod tests { params: None, }; let async_response = ThunderAsyncResponse::new_response(response); - assert_eq!(async_response.get_event(), Some("event_1".to_string())); + assert_eq!(async_response.get_method(), Some("event_1".to_string())); } #[tokio::test] @@ -510,13 +471,6 @@ mod tests { assert_eq!(device_resp_msg.unwrap().message, json!({"key": "value"})); } - #[tokio::test] - async fn test_thunder_async_client_get_id_from_result() { - let response = json!({"id": 42}).to_string(); - let id = ThunderAsyncClient::get_id_from_result(response.as_bytes()); - assert_ne!(id, Some(42)); - } - #[tokio::test] async fn test_thunder_async_client_prepare_request() { let (resp_tx, _resp_rx) = mpsc::channel(10); @@ -591,7 +545,7 @@ mod tests { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - thndr_asynclient: Some(client), + thunder_async_client: Some(client), broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunderbroker: true, diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 8b3c3dc9e..61a62173d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -63,7 +63,7 @@ use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; -use ripple_sdk::api::device::device_operator::{DeviceChannelRequest, DeviceResponseSubscription}; +use crate::client::thunder_async_client::{DeviceChannelRequest, DeviceResponseSubscription}; use ripple_sdk::tokio::sync::mpsc::Receiver; use std::sync::RwLock; use std::{env, process::Command}; @@ -84,8 +84,7 @@ impl ThunderClientManager { let client_c = client.clone(); tokio::spawn(async move { - if let Some(thndr_asynclient) = &client_c.thndr_asynclient { - println!("@@@NNA----> from thunder_client to async start call...."); + if let Some(thndr_asynclient) = &client_c.thunder_async_client { thndr_asynclient .start(&thndr_endpoint_url, request_tr) .await; @@ -94,42 +93,19 @@ impl ThunderClientManager { }); /*thunder async response will get here */ tokio::spawn(async move { - println!("@@@NNA----> in thunder::manage response block entrance..."); while let Some(response) = response_tr.recv().await { - println!( - "@@@NNA...manage fn response block..with response{:?}", - response - ); if let Some(id) = response.get_id() { - println!("@@@NNA...manage fn response id: {:?}", id); - if let Some(cb) = client.clone().broker_callbacks { - println!( - "@@@NNA...manage fn broker_callbacks check inside..callback:{:?}", - cb - ); - let mut callback = cb.write().unwrap(); - println!( - "@@@NNA.... after cb.write fn unwrap callback: {:?}", - callback - ); - if let Some(Some(c)) = callback.remove(&id) { - println!("@@@NNA...manage fn after callback.remove.."); + if let Some(broker_callbacks) = client.clone().broker_callbacks { + let mut callbacks = broker_callbacks.write().unwrap(); + if let Some(Some(callback)) = callbacks.remove(&id) { if let Some(resp) = response.get_device_resp_msg(None) { - println!("@@@NNA...deviceresponse {:?}", resp); - println!("@@@NNA...onshot send to sender tx: {:?}", c); - oneshot_send_and_log(c, resp, "ThunderResponse"); + oneshot_send_and_log(callback, resp, "ThunderResponse"); }; } } - } else if let Some(event_name) = response.get_event() { - println!("@@@NNA...manage fn response event {:?}", event_name); + } else if let Some(event_name) = response.get_method() { if let Some(broker_subs) = client.clone().broker_subscriptions { - println!( - "@@@NNA...after broker_subscriptions check.. broker_subs:{:?} ", - broker_subs - ); let subs = { - println!("@@@@NNA,,, in subs check with subs"); let mut br_subs = broker_subs.write().unwrap(); br_subs.get_mut(&event_name).cloned() }; @@ -140,10 +116,6 @@ impl ThunderClientManager { if let Some(resp_msg) = response.get_device_resp_msg(dev_resp_sub.clone().sub_id) { - println!( - "@@NNA....after get_device_resp_msg() with resp_msg:{:?}", - resp_msg - ); mpsc_send_and_log(s, resp_msg, "ThunderResponse").await; } } @@ -256,7 +228,7 @@ pub struct ThunderClient { pub id: Uuid, pub plugin_manager_tx: Option>, pub subscriptions: Option>>>, - pub thndr_asynclient: Option, + pub thunder_async_client: Option, pub broker_subscriptions: Option>>, pub broker_callbacks: Option>>, pub use_thunderbroker: bool, @@ -294,60 +266,17 @@ impl DeviceOperator for ThunderClient { params: request.params, callback: tx, }); - println!( - "@@@NNA---->in DeviceOperator::call req with msg{:?}", - message - ); self.send_message(message).await; - // match rx.await { - // Ok(response) => response, - // Err(_) => DeviceResponseMessage { - // message: Value::Null, - // sub_id: None, - // }, - // } - match rx.await { - Ok(response) => { - println!( - "@@@NNA....thunderclient deviceoperator response received:{:?}", - response - ); - response - } - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, - } + rx.await.unwrap() } else { let (tx, rx) = oneshot::channel::(); let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Call(request)); - self.add_to_callback(&async_request, tx); - - println!( - "@@@NNA---->in DeviceOperator::call req with msg{:?}", - async_request - ); - if let Some(async_client) = &self.thndr_asynclient { + self.add_callback(&async_request, tx); + if let Some(async_client) = &self.thunder_async_client { async_client.send(async_request).await; } - println!("@@@NNA----->after deviceoperator call send fn .."); - - match rx.await { - Ok(response) => { - println!("@@@NNA....deviceoperator response received:{:?}", response); - response - } - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, - } - // DeviceResponseMessage { - // message: Value::Null, - // sub_id: None, - // } + rx.await.unwrap() } } @@ -367,56 +296,17 @@ impl DeviceOperator for ThunderClient { sub_id: request.sub_id, }; let msg = ThunderMessage::ThunderSubscribeMessage(message); - println!( - "@@@NNA---->in DeviceOperator::subscribe req with msg{:?}", - msg - ); self.send_message(msg).await; - println!("****deviceoperator subscribe request waiting for response..."); - //rx.await.unwrap() - match rx.await { - Ok(response) => { - println!( - "@@@NNA....thunderclient deviceoperator subscription response received:{:?}", - response - ); - response - } - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, - } - } else if let Some(subscribe_request) = self.check_sub(&request, handler.clone()) { + rx.await.unwrap() + } else if let Some(subscribe_request) = + self.add_subscription_handler(&request, handler.clone()) + { let (tx, rx) = oneshot::channel::(); - self.add_to_callback(&subscribe_request, tx); - println!( - "@@@NNA---->in DeviceOperator::subscribe req with msg{:?}", - subscribe_request - ); - if let Some(async_client) = &self.thndr_asynclient { + self.add_callback(&subscribe_request, tx); + if let Some(async_client) = &self.thunder_async_client { async_client.send(subscribe_request).await; } - println!("@@@NNA----> subscribe request waiting for response..."); - - match rx.await { - Ok(response) => { - println!( - "@@@NNA....deviceoperator subscription response received:{:?}", - response - ); - response - } - Err(_) => DeviceResponseMessage { - message: Value::Null, - sub_id: None, - }, - } - //rx.await.unwrap() - // DeviceResponseMessage { - // message: Value::Null, - // sub_id: None, - // } + rx.await.unwrap() } else { DeviceResponseMessage { message: Value::Null, @@ -679,7 +569,7 @@ impl ThunderClient { None } - fn add_to_callback( + fn add_callback( &self, request: &ThunderAsyncRequest, dev_resp_callback: Sender, @@ -688,45 +578,38 @@ impl ThunderClient { callbacks.insert(request.id, Some(dev_resp_callback)); } - // if already subscibed updated handlers - fn check_sub( + // if already subscribed updated handlers + fn add_subscription_handler( &self, request: &DeviceSubscribeRequest, handler: MpscSender, ) -> Option { - println!("@@@NNA----> in check_sub function"); let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); + + // Create a key for the subscription based on the event name let key = format!("client.events.{}", request.event_name); - if let Some(subs) = broker_subscriptions.get_mut(&key) { - println!( - "@@@NNA----> Adding handler to existing subscription for key: {}", - key - ); + // Check if there are existing subscriptions for the given key + if let Some(subs) = broker_subscriptions.get_mut(&key) { + // If a subscription exists, add the handler to the list of handlers subs.handlers.push(handler); None } else { + // If no subscription exists, create a new async request for subscription let async_request = ThunderAsyncRequest::new(DeviceChannelRequest::Subscribe(request.clone())); - println!( - "@@@NNA----> async_request: {:?}, broker_subscriptions: {:?}", - async_request, broker_subscriptions - ); + // Create a new DeviceResponseSubscription with the handler let dev_resp_sub = DeviceResponseSubscription { sub_id: request.clone().sub_id, handlers: vec![handler], }; + // Insert the new subscription into the broker_subscriptions map broker_subscriptions.insert(key, dev_resp_sub); Some(async_request) } } - - // if only one handler cleanup - // fn check_unsub(&self, request: &DeviceUnsubscribeRequest) -> Option { - // None - // } } impl ThunderClientBuilder { @@ -793,7 +676,7 @@ impl ThunderClientBuilder { } pub async fn get_client( - url: Option, + url: Url, plugin_manager_tx: Option>, pool_tx: Option>, thunder_connection_state: Option>, @@ -803,26 +686,15 @@ impl ThunderClientBuilder { if !use_thndrbroker { let uid = Uuid::new_v4(); - if let Some(ref url) = url { - info!("initiating thunder connection {}", url); - } else { - error!("URL is None, cannot initiate thunder connection"); - return Err(RippleError::BootstrapError); - } + info!("initiating thunder connection URL:{} ", url); + let subscriptions = Arc::new(Mutex::new(HashMap::::default())); let (s, mut r) = mpsc::channel::(32); let pmtx_c = plugin_manager_tx.clone(); - let client = match url { - Some(url) => { - Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()) - .await - } - None => { - error!("URL is None, cannot initiate thunder connection"); - return Err(RippleError::BootstrapError); - } - }; + let client = + Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()).await; + // add error handling here if client.is_err() { error!("Unable to connect to thunder: {client:?}"); @@ -928,7 +800,7 @@ impl ThunderClientBuilder { id: uid, plugin_manager_tx: pmtx_c, subscriptions: Some(subscriptions), - thndr_asynclient: None, + thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, use_thunderbroker: false, @@ -946,7 +818,7 @@ impl ThunderClientBuilder { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - thndr_asynclient: Some(client), + thunder_async_client: Some(client), broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunderbroker: true, @@ -956,7 +828,7 @@ impl ThunderClientBuilder { thunder_client.clone(), broker_rx, resp_rx, - url.unwrap().to_string(), + url.to_string(), ); Ok(thunder_client) } @@ -970,7 +842,7 @@ impl ThunderClientBuilder { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - thndr_asynclient: None, + thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, use_thunderbroker: false, diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 2b5c12d9c..81dce5489 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -66,7 +66,7 @@ impl ThunderClientPool { let mut clients = Vec::default(); for _ in 0..size { let client = ThunderClientBuilder::get_client( - Some(url.clone()), + url.clone(), plugin_manager_tx.clone(), Some(s.clone()), thunder_connection_state.clone(), @@ -132,7 +132,7 @@ impl ThunderClientPool { let i = itr.position(|x| x.client.id == client_id); if let Some(index) = i { let client = ThunderClientBuilder::get_client( - Some(url.clone()), + url.clone(), plugin_manager_tx.clone(), Some(sender_for_thread.clone()), thunder_connection_state.clone(), @@ -161,7 +161,7 @@ impl ThunderClientPool { id: Uuid::new_v4(), plugin_manager_tx: pmtx_c, subscriptions: None, - thndr_asynclient: None, + thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, use_thunderbroker: false, diff --git a/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs index 96d9eca98..70dc4ffa4 100644 --- a/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs +++ b/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs @@ -27,12 +27,11 @@ use ripple_sdk::{ tokio::sync::mpsc::Sender, utils::error::RippleError, }; -use serde::{Deserialize, Serialize}; -use serde_json::json; - -use crate::utils::get_next_id; use super::thunder_async_client::{ThunderAsyncRequest, ThunderAsyncResponse}; +use ripple_sdk::utils::rpc_utils::get_next_id; +use serde::{Deserialize, Serialize}; +use serde_json::json; #[derive(Clone, Debug)] pub struct BrokerSender { 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 0faba38b6..d16d6cd66 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -1134,7 +1134,7 @@ pub mod tests { subscriptions: None, broker_callbacks: None, broker_subscriptions: None, - thndr_asynclient: None, + thunder_async_client: None, use_thunderbroker: false, }; let mut sessions: HashMap = HashMap::new(); @@ -1171,7 +1171,7 @@ pub mod tests { subscriptions: None, broker_callbacks: None, broker_subscriptions: None, - thndr_asynclient: None, + thunder_async_client: None, use_thunderbroker: false, }; let mut sessions: HashMap = HashMap::new(); 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 8f19d0a74..c639e448d 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -173,7 +173,7 @@ impl MockThunderController { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - thndr_asynclient: None, + thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, use_thunderbroker: false, diff --git a/device/thunder_ripple_sdk/src/thunder_state.rs b/device/thunder_ripple_sdk/src/thunder_state.rs index 19cabb76f..8388a504a 100644 --- a/device/thunder_ripple_sdk/src/thunder_state.rs +++ b/device/thunder_ripple_sdk/src/thunder_state.rs @@ -60,7 +60,7 @@ impl ThunderConnectionState { #[derive(Debug, Clone)] pub struct ThunderBootstrapStateWithConfig { pub extn_client: ExtnClient, - pub url: Option, + pub url: Url, pub pool_size: Option, pub plugin_param: Option, pub thunder_connection_state: Option>, diff --git a/device/thunder_ripple_sdk/src/utils.rs b/device/thunder_ripple_sdk/src/utils.rs index e5de2aef4..a9d38a7ef 100644 --- a/device/thunder_ripple_sdk/src/utils.rs +++ b/device/thunder_ripple_sdk/src/utils.rs @@ -15,10 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::{ - collections::HashMap, - sync::atomic::{AtomicU64, Ordering}, -}; +use std::collections::HashMap; use jsonrpsee::core::Error; use ripple_sdk::{ @@ -112,10 +109,3 @@ pub fn get_error_value(error: &Error) -> Value { } Value::Null } - -static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); - -pub fn get_next_id() -> u64 { - ATOMIC_ID.fetch_add(1, Ordering::Relaxed); - ATOMIC_ID.load(Ordering::Relaxed) -} From c806670f13df4e4b5bd217adbf6b8ae325f5f7c5 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 7 Jan 2025 19:23:41 +0530 Subject: [PATCH 22/51] Trigger Concourse From ed7270cbf3b4fb42ec99f4f98e6e6dde30d72362 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 12:20:44 +0530 Subject: [PATCH 23/51] fix: review comments fixed. --- core/main/src/processor/metrics_processor.rs | 5 +- core/sdk/src/api/device/device_operator.rs | 41 +++++++++++++++++ .../src/bootstrap/boot_thunder.rs | 2 +- .../src/client/thunder_async_client.rs | 46 +------------------ .../src/client/thunder_client.rs | 5 +- .../src/client/thunder_client_pool.rs | 4 +- 6 files changed, 52 insertions(+), 51 deletions(-) diff --git a/core/main/src/processor/metrics_processor.rs b/core/main/src/processor/metrics_processor.rs index 201d9260f..921e85478 100644 --- a/core/main/src/processor/metrics_processor.rs +++ b/core/main/src/processor/metrics_processor.rs @@ -214,7 +214,10 @@ impl ExtnRequestProcessor for MetricsProcessor { } } MetricsPayload::TelemetryPayload(t) => { - TelemetryBuilder::update_session_id_and_send_telemetry(&state, t).is_ok() + 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, } diff --git a/core/sdk/src/api/device/device_operator.rs b/core/sdk/src/api/device/device_operator.rs index 10b2e9e29..fdbd597d8 100644 --- a/core/sdk/src/api/device/device_operator.rs +++ b/core/sdk/src/api/device/device_operator.rs @@ -38,6 +38,47 @@ pub trait DeviceOperator: Clone { async fn unsubscribe(&self, request: DeviceUnsubscribeRequest); } + +#[derive(Debug, Clone)] +pub struct DeviceResponseSubscription { + pub sub_id: Option, + pub handlers: Vec>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum DeviceChannelRequest { + Call(DeviceCallRequest), + Subscribe(DeviceSubscribeRequest), + Unsubscribe(DeviceUnsubscribeRequest), +} + +impl DeviceChannelRequest { + pub fn get_callsign_method(&self) -> (String, String) { + match self { + DeviceChannelRequest::Call(c) => { + let mut collection: Vec<&str> = c.method.split('.').collect(); + let method = collection.pop().unwrap_or_default(); + let callsign = collection.join("."); + (callsign, method.into()) + } + DeviceChannelRequest::Subscribe(s) => (s.module.clone(), s.event_name.clone()), + DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), + } + } + + pub fn is_subscription(&self) -> bool { + !matches!(self, DeviceChannelRequest::Call(_)) + } + + pub fn is_unsubscribe(&self) -> Option { + if let DeviceChannelRequest::Unsubscribe(u) = self { + Some(u.clone()) + } else { + None + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeviceCallRequest { pub method: String, diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index a52837844..5d85403c8 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -88,7 +88,7 @@ pub async fn boot_thunder( } if let Ok(thndr_client) = - ThunderClientBuilder::get_client(gateway_url.clone(), None, None, None, None, true) + ThunderClientBuilder::start_thunder_client(gateway_url.clone(), None, None, None, None, true) .await { let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index e6cfb6632..23cd451f5 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -23,10 +23,7 @@ use futures_util::{SinkExt, StreamExt}; use ripple_sdk::api::device::device_operator::DeviceResponseMessage; use ripple_sdk::{ api::{ - device::device_operator::{ - DeviceCallRequest, DeviceSubscribeRequest, DeviceUnsubscribeRequest, - }, - gateway::rpc_gateway_api::JsonRpcApiResponse, + device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, }, log::{debug, error, info}, tokio::{self, net::TcpStream, sync::mpsc::Receiver}, @@ -35,50 +32,9 @@ use ripple_sdk::{ rpc_utils::{extract_tcp_port, get_next_id}, }, }; -use serde::{Deserialize, Serialize}; use serde_json::json; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; -#[derive(Debug, Clone)] -pub struct DeviceResponseSubscription { - pub sub_id: Option, - pub handlers: Vec>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum DeviceChannelRequest { - Call(DeviceCallRequest), - Subscribe(DeviceSubscribeRequest), - Unsubscribe(DeviceUnsubscribeRequest), -} - -impl DeviceChannelRequest { - pub fn get_callsign_method(&self) -> (String, String) { - match self { - DeviceChannelRequest::Call(c) => { - let mut collection: Vec<&str> = c.method.split('.').collect(); - let method = collection.pop().unwrap_or_default(); - let callsign = collection.join("."); - (callsign, method.into()) - } - DeviceChannelRequest::Subscribe(s) => (s.module.clone(), s.event_name.clone()), - DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), - } - } - - pub fn is_subscription(&self) -> bool { - !matches!(self, DeviceChannelRequest::Call(_)) - } - - pub fn is_unsubscribe(&self) -> Option { - if let DeviceChannelRequest::Unsubscribe(u) = self { - Some(u.clone()) - } else { - None - } - } -} - #[derive(Clone, Debug)] pub struct ThunderAsyncClient { status_manager: StatusManager, diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 61a62173d..cb3fb29a2 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -63,7 +63,7 @@ use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; -use crate::client::thunder_async_client::{DeviceChannelRequest, DeviceResponseSubscription}; +use ripple_sdk::api::device::device_operator::{DeviceChannelRequest, DeviceResponseSubscription}; use ripple_sdk::tokio::sync::mpsc::Receiver; use std::sync::RwLock; use std::{env, process::Command}; @@ -626,6 +626,7 @@ impl ThunderClientBuilder { } None } + async fn create_client( url: Url, thunder_connection_state: Arc, @@ -675,7 +676,7 @@ impl ThunderClientBuilder { client } - pub async fn get_client( + pub async fn start_thunder_client( url: Url, plugin_manager_tx: Option>, pool_tx: Option>, diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 81dce5489..2d5ab619e 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -65,7 +65,7 @@ impl ThunderClientPool { let thunder_connection_state = thunder_connection_state.clone(); let mut clients = Vec::default(); for _ in 0..size { - let client = ThunderClientBuilder::get_client( + let client = ThunderClientBuilder::start_thunder_client( url.clone(), plugin_manager_tx.clone(), Some(s.clone()), @@ -131,7 +131,7 @@ impl ThunderClientPool { let mut itr = pool.clients.iter(); let i = itr.position(|x| x.client.id == client_id); if let Some(index) = i { - let client = ThunderClientBuilder::get_client( + let client = ThunderClientBuilder::start_thunder_client( url.clone(), plugin_manager_tx.clone(), Some(sender_for_thread.clone()), From b5e9c9e8beb174904c34d212950c90c23846350b Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 12:48:19 +0530 Subject: [PATCH 24/51] fix: format check failure fix --- .../src/bootstrap/boot_thunder.rs | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 5d85403c8..10331a7d7 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -22,6 +22,7 @@ use crate::{ use ripple_sdk::{ extn::client::extn_client::ExtnClient, log::{debug, error, info, warn}, + serde_json::{self, Error}, }; use super::{get_config_step::ThunderGetConfigStep, setup_thunder_pool_step::ThunderPoolStep}; @@ -61,25 +62,22 @@ pub async fn boot_thunder( if let Ok(message) = extn_message_response { if let Some(ExtnResponse::Value(v)) = message.payload.extract() { - match serde_json::from_value::(v) { - Ok(thunder_parameters) => match url::Url::parse(&thunder_parameters.gateway) { - Ok(gtway_url) => { - debug!("Got url:{} from device manifest", gtway_url); - gateway_url = gtway_url; - } - Err(_) => { - warn!( - "Could not parse thunder gateway '{}', using default {}", - thunder_parameters.gateway, GATEWAY_DEFAULT - ); - } - }, - Err(_) => { + let tp_res: Result = serde_json::from_value(v); + if let Ok(thunder_parameters) = tp_res { + if let Ok(gtway_url) = url::Url::parse(&thunder_parameters.gateway) { + debug!("Got url from device manifest"); + gateway_url = gtway_url + } else { warn!( - "Could not read thunder platform parameters, using default {}", - GATEWAY_DEFAULT + "Could not parse thunder gateway '{}', using default {}", + thunder_parameters.gateway, GATEWAY_DEFAULT ); } + } else { + warn!( + "Could not read thunder platform parameters, using default {}", + GATEWAY_DEFAULT + ); } if let Ok(host_override) = std::env::var("DEVICE_HOST") { gateway_url.set_host(Some(&host_override)).ok(); @@ -87,9 +85,15 @@ pub async fn boot_thunder( } } - if let Ok(thndr_client) = - ThunderClientBuilder::start_thunder_client(gateway_url.clone(), None, None, None, None, true) - .await + if let Ok(thndr_client) = ThunderClientBuilder::start_thunder_client( + gateway_url.clone(), + None, + None, + None, + None, + true, + ) + .await { let thunder_state = ThunderState::new(ext_client.clone(), thndr_client); From 566453538b3e438dd6cab2fa8c9a4b637ae51499 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 19:49:24 +0530 Subject: [PATCH 25/51] chore: renaming, cleanup done for better readability. --- .../src/client/thunder_client.rs | 257 +++++++++--------- 1 file changed, 134 insertions(+), 123 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index cb3fb29a2..763617f6e 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -75,7 +75,7 @@ pub type BrokerCallbackMap = HashMap, mut response_tr: Receiver, @@ -627,6 +627,129 @@ impl ThunderClientBuilder { None } + async fn start_thunderpool_client( + url: Url, + plugin_manager_tx: Option>, + pool_tx: Option>, + thunder_connection_state: Option>, + existing_client: Option, + ) -> Result { + let uid = Uuid::new_v4(); + info!("initiating thunder connection URL:{} ", url); + + let subscriptions = Arc::new(Mutex::new(HashMap::::default())); + let (s, mut r) = mpsc::channel::(32); + let pmtx_c = plugin_manager_tx.clone(); + let client = + Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()).await; + + // add error handling here + if client.is_err() { + error!("Unable to connect to thunder: {client:?}"); + return Err(RippleError::BootstrapError); + } + + let client = client.unwrap(); + let subscriptions_c = subscriptions.clone(); + tokio::spawn(async move { + while let Some(message) = r.recv().await { + if !client.is_connected() { + if let Some(ptx) = pool_tx { + warn!( + "Client {} became disconnected, removing from pool message {:?}", + uid, message + ); + // Remove the client and then try the message again with a new client + let pool_msg = ThunderPoolCommand::ResetThunderClient(uid); + mpsc_send_and_log(&ptx, pool_msg, "ResetThunderClient").await; + let pool_msg = ThunderPoolCommand::ThunderMessage(message); + mpsc_send_and_log(&ptx, pool_msg, "RetryThunderMessage").await; + return; + } + } + info!("Client {} sending thunder message {:?}", uid, message); + match message { + ThunderMessage::ThunderCallMessage(thunder_message) => { + ThunderClient::call(&client, thunder_message, plugin_manager_tx.clone()) + .await; + } + ThunderMessage::ThunderSubscribeMessage(thunder_message) => { + ThunderClient::subscribe( + uid, + &client, + &subscriptions_c, + thunder_message, + plugin_manager_tx.clone(), + pool_tx.clone(), + ) + .await; + } + ThunderMessage::ThunderUnsubscribeMessage(thunder_message) => { + ThunderClient::unsubscribe(&client, &subscriptions_c, thunder_message) + .await; + } + } + } + }); + + if let Some(old_client) = existing_client { + // Re-subscribe for each subscription that was active on the old client + if let Some(subscriptions) = old_client.subscriptions { + // Reactivate the plugin state + let (plugin_rdy_tx, plugin_rdy_rx) = oneshot::channel::(); + if let Some(tx) = pmtx_c.clone() { + let msg = PluginManagerCommand::ReactivatePluginState { tx: plugin_rdy_tx }; + mpsc_send_and_log(&tx, msg, "ResetPluginState").await; + if let Ok(res) = plugin_rdy_rx.await { + res.ready().await; + } + } + let mut subs = subscriptions.lock().await; + for (subscribe_method, tsub) in subs.iter_mut() { + let mut listeners = + HashMap::>::default(); + std::mem::swap(&mut listeners, &mut tsub.listeners); + for (sub_id, listener) in listeners { + let thunder_message: ThunderSubscribeMessage = { + Self::parse_subscribe_method(subscribe_method) + .map(|(module, event_name)| ThunderSubscribeMessage { + module, + event_name, + params: tsub.params.clone(), + handler: listener, + callback: None, + sub_id: Some(sub_id), + }) + .unwrap() + }; + let resp = s + .send(ThunderMessage::ThunderSubscribeMessage(thunder_message)) + .await; + if resp.is_err() { + if let Some((module, _)) = + Self::parse_subscribe_method(subscribe_method) + { + error!("Failed to send re-subscribe message for {}", module); + } + } + } + } + } + } + + Ok(ThunderClient { + sender: Some(s), + pooled_sender: None, + id: uid, + plugin_manager_tx: pmtx_c, + subscriptions: Some(subscriptions), + thunder_async_client: None, + broker_subscriptions: None, + broker_callbacks: None, + use_thunderbroker: false, + }) + } + async fn create_client( url: Url, thunder_connection_state: Arc, @@ -685,127 +808,15 @@ impl ThunderClientBuilder { use_thndrbroker: bool, ) -> Result { if !use_thndrbroker { - let uid = Uuid::new_v4(); - - info!("initiating thunder connection URL:{} ", url); - - let subscriptions = - Arc::new(Mutex::new(HashMap::::default())); - let (s, mut r) = mpsc::channel::(32); - let pmtx_c = plugin_manager_tx.clone(); - let client = - Self::create_client(url.clone(), thunder_connection_state.clone().unwrap()).await; - - // add error handling here - if client.is_err() { - error!("Unable to connect to thunder: {client:?}"); - return Err(RippleError::BootstrapError); - } - - let client = client.unwrap(); - let subscriptions_c = subscriptions.clone(); - tokio::spawn(async move { - while let Some(message) = r.recv().await { - if !client.is_connected() { - if let Some(ptx) = pool_tx { - warn!( - "Client {} became disconnected, removing from pool message {:?}", - uid, message - ); - // Remove the client and then try the message again with a new client - let pool_msg = ThunderPoolCommand::ResetThunderClient(uid); - mpsc_send_and_log(&ptx, pool_msg, "ResetThunderClient").await; - let pool_msg = ThunderPoolCommand::ThunderMessage(message); - mpsc_send_and_log(&ptx, pool_msg, "RetryThunderMessage").await; - return; - } - } - info!("Client {} sending thunder message {:?}", uid, message); - match message { - ThunderMessage::ThunderCallMessage(thunder_message) => { - ThunderClient::call( - &client, - thunder_message, - plugin_manager_tx.clone(), - ) - .await; - } - ThunderMessage::ThunderSubscribeMessage(thunder_message) => { - ThunderClient::subscribe( - uid, - &client, - &subscriptions_c, - thunder_message, - plugin_manager_tx.clone(), - pool_tx.clone(), - ) - .await; - } - ThunderMessage::ThunderUnsubscribeMessage(thunder_message) => { - ThunderClient::unsubscribe(&client, &subscriptions_c, thunder_message) - .await; - } - } - } - }); - - if let Some(old_client) = existing_client { - // Re-subscribe for each subscription that was active on the old client - if let Some(subscriptions) = old_client.subscriptions { - // Reactivate the plugin state - let (plugin_rdy_tx, plugin_rdy_rx) = - oneshot::channel::(); - if let Some(tx) = pmtx_c.clone() { - let msg = PluginManagerCommand::ReactivatePluginState { tx: plugin_rdy_tx }; - mpsc_send_and_log(&tx, msg, "ResetPluginState").await; - if let Ok(res) = plugin_rdy_rx.await { - res.ready().await; - } - } - let mut subs = subscriptions.lock().await; - for (subscribe_method, tsub) in subs.iter_mut() { - let mut listeners = - HashMap::>::default(); - std::mem::swap(&mut listeners, &mut tsub.listeners); - for (sub_id, listener) in listeners { - let thunder_message: ThunderSubscribeMessage = { - Self::parse_subscribe_method(subscribe_method) - .map(|(module, event_name)| ThunderSubscribeMessage { - module, - event_name, - params: tsub.params.clone(), - handler: listener, - callback: None, - sub_id: Some(sub_id), - }) - .unwrap() - }; - let resp = s - .send(ThunderMessage::ThunderSubscribeMessage(thunder_message)) - .await; - if resp.is_err() { - if let Some((module, _)) = - Self::parse_subscribe_method(subscribe_method) - { - error!("Failed to send re-subscribe message for {}", module); - } - } - } - } - } - } - - Ok(ThunderClient { - sender: Some(s), - pooled_sender: None, - id: uid, - plugin_manager_tx: pmtx_c, - subscriptions: Some(subscriptions), - thunder_async_client: None, - broker_subscriptions: None, - broker_callbacks: None, - use_thunderbroker: false, - }) + let client = Self::start_thunderpool_client( + url, + plugin_manager_tx, + pool_tx, + thunder_connection_state, + existing_client, + ) + .await; + client } else { let (resp_tx, resp_rx) = mpsc::channel(10); let callback = BrokerCallback { sender: resp_tx }; @@ -825,7 +836,7 @@ impl ThunderClientBuilder { use_thunderbroker: true, }; - ThunderClientManager::manage( + ThunderClientManager::start( thunder_client.clone(), broker_rx, resp_rx, From 2609d4d4a1051033d4fedbc710516aa2fa3ccb47 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 20:15:17 +0530 Subject: [PATCH 26/51] chore: clippy error fixed --- device/thunder_ripple_sdk/src/client/thunder_client.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 763617f6e..bf8b29db3 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -808,15 +808,14 @@ impl ThunderClientBuilder { use_thndrbroker: bool, ) -> Result { if !use_thndrbroker { - let client = Self::start_thunderpool_client( + Self::start_thunderpool_client( url, plugin_manager_tx, pool_tx, thunder_connection_state, existing_client, ) - .await; - client + .await } else { let (resp_tx, resp_rx) = mpsc::channel(10); let callback = BrokerCallback { sender: resp_tx }; From 26588b6d7ba89f9830cf54c10ed73257c3207eff Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 20:46:53 +0530 Subject: [PATCH 27/51] fix: review comment fixed --- .../src/bootstrap/boot_thunder.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 10331a7d7..7dcb76ce6 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -53,7 +53,7 @@ pub async fn boot_thunder( ) -> Option { info!("Booting thunder initiated"); //by default enabling the thunderBroker - if ext_client.get_bool_config("use_with_thunder_broker") { + let state = if ext_client.get_bool_config("use_with_thunder_broker") { info!("Using thunder broker"); let mut extn_client = ext_client.clone(); let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); @@ -112,21 +112,26 @@ pub async fn boot_thunder( thndr_boot_stateclient.clone().state.start_event_thread(); - SetupThunderProcessor::setup(thndr_boot_stateclient.clone()).await; - return Some(thndr_boot_stateclient); + Some(thndr_boot_stateclient) + } else { + None } - None } else { if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { if let Ok(state) = ThunderPoolStep::setup(state).await { - SetupThunderProcessor::setup(state.clone()).await; - return Some(state); + Some(state) } else { error!("Unable to connect to Thunder, error in ThunderPoolStep"); + None } } else { error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); + None } - None + }; + + if let Some(s) = state.clone() { + SetupThunderProcessor::setup(s).await; } + state } From 7242e40b78143f911a3412c692e58246defa895f Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 8 Jan 2025 21:13:27 +0530 Subject: [PATCH 28/51] fix: clippy error fixed --- .../src/bootstrap/boot_thunder.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 7dcb76ce6..6b570ba1a 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -116,18 +116,16 @@ pub async fn boot_thunder( } else { None } - } else { - if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { - if let Ok(state) = ThunderPoolStep::setup(state).await { - Some(state) - } else { - error!("Unable to connect to Thunder, error in ThunderPoolStep"); - None - } + } else if let Ok(state) = ThunderGetConfigStep::setup(ext_client, plugin_param).await { + if let Ok(state) = ThunderPoolStep::setup(state).await { + Some(state) } else { - error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); + error!("Unable to connect to Thunder, error in ThunderPoolStep"); None } + } else { + error!("Unable to connect to Thunder, error in ThunderGetConfigStep"); + None }; if let Some(s) = state.clone() { From 1b7016d1da2e7e045a105f0c9ca96cddc8892e40 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 9 Jan 2025 11:16:55 +0530 Subject: [PATCH 29/51] fix: review comment fixed. --- .../src/bootstrap/boot_thunder.rs | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index 6b570ba1a..cad94add5 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -22,7 +22,6 @@ use crate::{ use ripple_sdk::{ extn::client::extn_client::ExtnClient, log::{debug, error, info, warn}, - serde_json::{self, Error}, }; use super::{get_config_step::ThunderGetConfigStep, setup_thunder_pool_step::ThunderPoolStep}; @@ -61,28 +60,34 @@ pub async fn boot_thunder( extn_client.request(Config::PlatformParameters).await; if let Ok(message) = extn_message_response { - if let Some(ExtnResponse::Value(v)) = message.payload.extract() { - let tp_res: Result = serde_json::from_value(v); - if let Ok(thunder_parameters) = tp_res { - if let Ok(gtway_url) = url::Url::parse(&thunder_parameters.gateway) { - debug!("Got url from device manifest"); - gateway_url = gtway_url - } else { - warn!( - "Could not parse thunder gateway '{}', using default {}", - thunder_parameters.gateway, GATEWAY_DEFAULT - ); - } - } else { - warn!( - "Could not read thunder platform parameters, using default {}", - GATEWAY_DEFAULT - ); + if let Some(_response) = message.payload.extract().map(|response| { + if let ExtnResponse::Value(v) = response { + serde_json::from_value::(v) + .map(|thunder_parameters| { + url::Url::parse(&thunder_parameters.gateway).map_or_else( + |_| { + warn!( + "Could not parse thunder gateway '{}', using default {}", + thunder_parameters.gateway, GATEWAY_DEFAULT + ); + }, + |gtway_url| { + debug!("Got url from device manifest"); + gateway_url = gtway_url; + }, + ); + }) + .unwrap_or_else(|_| { + warn!( + "Could not read thunder platform parameters, using default {}", + GATEWAY_DEFAULT + ); + }); } if let Ok(host_override) = std::env::var("DEVICE_HOST") { gateway_url.set_host(Some(&host_override)).ok(); } - } + }) {} } if let Ok(thndr_client) = ThunderClientBuilder::start_thunder_client( From c345b4cc74bc5344504918215a5f661c999b949c Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 15 Jan 2025 11:29:07 +0530 Subject: [PATCH 30/51] chore: flag and one file name renamed for better readability. --- device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs | 2 +- device/thunder_ripple_sdk/src/client/thunder_async_client.rs | 2 +- ...status_mgr.rs => thunder_async_client_plugins_status_mgr.rs} | 0 device/thunder_ripple_sdk/src/client/thunder_client.rs | 2 +- device/thunder_ripple_sdk/src/lib.rs | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename device/thunder_ripple_sdk/src/client/{thunderbroker_plugins_status_mgr.rs => thunder_async_client_plugins_status_mgr.rs} (100%) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index cad94add5..b63612e94 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -52,7 +52,7 @@ pub async fn boot_thunder( ) -> Option { info!("Booting thunder initiated"); //by default enabling the thunderBroker - let state = if ext_client.get_bool_config("use_with_thunder_broker") { + let state = if ext_client.get_bool_config("use_with_thunder_async_client") { info!("Using thunder broker"); let mut extn_client = ext_client.clone(); let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 23cd451f5..b5d44fe96 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -17,7 +17,7 @@ use std::time::Duration; -use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; +use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; use ripple_sdk::api::device::device_operator::DeviceResponseMessage; diff --git a/device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs similarity index 100% rename from device/thunder_ripple_sdk/src/client/thunderbroker_plugins_status_mgr.rs rename to device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index bf8b29db3..6df887aa6 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -58,7 +58,7 @@ use url::Url; use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; use super::thunder_client_pool::ThunderPoolCommand; -use super::thunderbroker_plugins_status_mgr::{BrokerCallback, BrokerSender}; +use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender}; use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index 1c93ac43f..462f9dcdb 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -19,10 +19,10 @@ pub mod client { pub mod jsonrpc_method_locator; pub mod plugin_manager; pub mod thunder_async_client; + pub mod thunder_async_client_plugins_status_mgr; pub mod thunder_client; pub mod thunder_client_pool; pub mod thunder_plugin; - pub mod thunderbroker_plugins_status_mgr; } pub mod bootstrap { From 8d7771b7afb104bee8bfa9a0c7c0c387f0e2ef30 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 15 Jan 2025 13:53:11 +0530 Subject: [PATCH 31/51] fix: format check failure fix --- .../src/client/thunder_client.rs | 60 +++++++------------ 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 6df887aa6..6e41ab823 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -15,58 +15,44 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::{BTreeMap, HashMap}; -use std::str::FromStr; -use std::sync::Arc; - -use jsonrpsee::core::client::{Client, ClientT, SubscriptionClientT}; -use jsonrpsee::ws_client::WsClientBuilder; - +use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; +use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender}; +use super::thunder_client_pool::ThunderPoolCommand; +use super::{ + jsonrpc_method_locator::JsonRpcMethodLocator, + plugin_manager::{PluginActivatedResult, PluginManagerCommand}, +}; use crate::thunder_state::ThunderConnectionState; use crate::utils::get_error_value; +use jsonrpsee::core::client::{Client, ClientT, SubscriptionClientT}; use jsonrpsee::core::{async_trait, error::Error as JsonRpcError}; use jsonrpsee::types::ParamsSer; +use jsonrpsee::ws_client::WsClientBuilder; use regex::Regex; -use ripple_sdk::serde_json::json; -use ripple_sdk::{ - api::device::device_operator::DeviceResponseMessage, - tokio::sync::mpsc::{self, Sender as MpscSender}, - tokio::{sync::Mutex, task::JoinHandle, time::sleep}, -}; use ripple_sdk::{ api::device::device_operator::{ - DeviceCallRequest, DeviceSubscribeRequest, DeviceUnsubscribeRequest, + DeviceCallRequest, DeviceChannelParams, DeviceChannelRequest, DeviceOperator, + DeviceResponseMessage, DeviceResponseSubscription, DeviceSubscribeRequest, + DeviceUnsubscribeRequest, }, - serde_json::{self, Value}, - tokio, -}; -use ripple_sdk::{ - api::device::device_operator::{DeviceChannelParams, DeviceOperator}, - uuid::Uuid, -}; -use ripple_sdk::{ log::{error, info, warn}, - utils::channel_utils::{mpsc_send_and_log, oneshot_send_and_log}, -}; -use ripple_sdk::{ + serde_json::{self, json, Value}, + tokio, + tokio::sync::mpsc::{self, Receiver, Sender as MpscSender}, tokio::sync::oneshot::{self, Sender as OneShotSender}, + tokio::{sync::Mutex, task::JoinHandle, time::sleep}, + utils::channel_utils::{mpsc_send_and_log, oneshot_send_and_log}, utils::error::RippleError, + uuid::Uuid, }; use serde::{Deserialize, Serialize}; -use tokio::sync::oneshot::Sender; -use url::Url; - -use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; -use super::thunder_client_pool::ThunderPoolCommand; -use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender}; -use super::{ - jsonrpc_method_locator::JsonRpcMethodLocator, - plugin_manager::{PluginActivatedResult, PluginManagerCommand}, -}; -use ripple_sdk::api::device::device_operator::{DeviceChannelRequest, DeviceResponseSubscription}; -use ripple_sdk::tokio::sync::mpsc::Receiver; +use std::collections::{BTreeMap, HashMap}; +use std::str::FromStr; +use std::sync::Arc; use std::sync::RwLock; use std::{env, process::Command}; +use tokio::sync::oneshot::Sender; +use url::Url; pub type BrokerSubMap = HashMap; pub type BrokerCallbackMap = HashMap>>; From 58849cd29c0af948a1d35006afb99657cb300b82 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 15 Jan 2025 22:37:43 +0530 Subject: [PATCH 32/51] feat: added the new websocket for new thunder request in thunder_async_client --- .../src/bootstrap/boot_thunder.rs | 2 +- .../src/client/thunder_async_client.rs | 43 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index b63612e94..c41cfe0e3 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -53,7 +53,7 @@ pub async fn boot_thunder( info!("Booting thunder initiated"); //by default enabling the thunderBroker let state = if ext_client.get_bool_config("use_with_thunder_async_client") { - info!("Using thunder broker"); + info!("Using thunder_async_clinet"); let mut extn_client = ext_client.clone(); let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); let extn_message_response: Result = diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index b5d44fe96..be8387d1d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -277,7 +277,6 @@ impl ThunderAsyncClient { }, Err(e) => { error!("Broker Websocket error on read {:?}", e); - // Time to reconnect Thunder with existing subscription break; } } @@ -289,8 +288,46 @@ impl ThunderAsyncClient { Ok(updated_request) => { debug!("Sending request to broker {:?}", updated_request); for r in updated_request { - let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - let _flush = ws_tx.flush().await; + let url_clone = url.to_string(); + tokio::spawn({ + let client_c = client_c.clone(); + let callback = callback.clone(); + async move { + let (mut new_wtx, mut new_wrx) = Self::create_ws(&url_clone).await; + let _feed = new_wtx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + let _flush = new_wtx.flush().await; + + tokio::pin! { + let read = new_wrx.next(); + } + + loop { + tokio::select! { + Some(value) = &mut read => { + match value { + Ok(v) => { + if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { + client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; + } + else { + //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose + // send the incoming text without context back to the sender + Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + } + } + }, + Err(e) => { + error!("Broker Websocket error on read {:?}", e); + // Time to reconnect Thunder with existing subscription + break; + } + } + } + } + } + } + }); } } Err(e) => { From 08a7c3bcde3aa1cec63d73d0677e896777fee6d0 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 16 Jan 2025 12:43:39 +0530 Subject: [PATCH 33/51] fix: review comments fixed. --- .../src/bootstrap/setup_thunder_pool_step.rs | 12 +++++++++--- .../src/client/thunder_async_client.rs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs index cb55bad11..68149dd43 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/setup_thunder_pool_step.rs @@ -71,10 +71,16 @@ impl ThunderPoolStep { }; info!("Received Controller pool"); - let expected_plugins = state.plugin_param.clone(); + let expected_plugins = match state.plugin_param.clone() { + Some(plugins) => plugins, + None => { + error!("Expected plugins are not provided."); + return Err(RippleError::BootstrapError); + } + }; let tc = Box::new(controller_pool); let (plugin_manager_tx, failed_plugins) = - PluginManager::start(tc, expected_plugins.clone().unwrap()).await; + PluginManager::start(tc, expected_plugins.clone()).await; if !failed_plugins.is_empty() { error!( @@ -83,7 +89,7 @@ impl ThunderPoolStep { ); loop { let failed_plugins = PluginManager::activate_mandatory_plugins( - expected_plugins.as_ref().unwrap().clone(), + expected_plugins.clone(), plugin_manager_tx.clone(), ) .await; diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index be8387d1d..d7ec1a888 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -66,7 +66,7 @@ pub struct ThunderAsyncResponse { impl ThunderAsyncResponse { fn new_response(response: JsonRpcApiResponse) -> Self { Self { - id: None, + id: response.id, result: Ok(response), } } From d8ba964ed47aff9f57c2e4b4a372fe1ae120f951 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 17 Jan 2025 10:12:07 +0530 Subject: [PATCH 34/51] fix: review comment fixed. --- core/main/src/broker/endpoint_broker.rs | 5 -- .../src/client/thunder_async_client.rs | 74 +++++++++---------- .../src/client/thunder_client.rs | 18 ++--- .../src/client/thunder_client_pool.rs | 2 +- .../src/processors/thunder_package_manager.rs | 4 +- .../src/tests/mock_thunder_controller.rs | 2 +- 6 files changed, 49 insertions(+), 56 deletions(-) diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index ecdaa7e33..071bdfe1a 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -407,11 +407,6 @@ impl EndpointBrokerState { } } - // pub fn get_next_id() -> u64 { - // ATOMIC_ID.fetch_add(1, Ordering::Relaxed); - // ATOMIC_ID.load(Ordering::Relaxed) - // } - fn update_request( &self, rpc_request: &RpcRequest, diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index d7ec1a888..6ea07a5e1 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -63,6 +63,8 @@ pub struct ThunderAsyncResponse { pub result: Result, } +impl ThunderAsyncClient {} + impl ThunderAsyncResponse { fn new_response(response: JsonRpcApiResponse) -> Self { Self { @@ -236,6 +238,34 @@ impl ThunderAsyncClient { } } + pub async fn process_new_req(&self, request: String, url: String, callback: BrokerCallback) { + let (mut new_wtx, mut new_wrx) = Self::create_ws(&url).await; + let _feed = new_wtx + .feed(tokio_tungstenite::tungstenite::Message::Text(request)) + .await; + let _flush = new_wtx.flush().await; + + tokio::pin! { + let read = new_wrx.next(); + } + + tokio::select! { + Some(value) = &mut read => { + match value { + Ok(v) => { + if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + // send the incoming text without context back to the sender + Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + } + }, + Err(e) => { + error!("thunder_async_client Websocket error on read {:?}", e); + } + } + } + } + } + pub async fn start( &self, url: &str, @@ -282,50 +312,18 @@ impl ThunderAsyncClient { } }, Some(request) = tr.recv() => { - debug!("Got request from receiver for broker {:?}", request); + debug!("Got request from receiver for thunder {:?}", request); // here prepare_request will check the plugin status and add json rpc format match client_c.prepare_request(&request) { Ok(updated_request) => { - debug!("Sending request to broker {:?}", updated_request); + debug!("Sending request to thunder {:?}", updated_request); for r in updated_request { let url_clone = url.to_string(); + let callback_clone = callback.clone(); + let self_clone = self.clone(); tokio::spawn({ - let client_c = client_c.clone(); - let callback = callback.clone(); async move { - let (mut new_wtx, mut new_wrx) = Self::create_ws(&url_clone).await; - let _feed = new_wtx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - let _flush = new_wtx.flush().await; - - tokio::pin! { - let read = new_wrx.next(); - } - - loop { - tokio::select! { - Some(value) = &mut read => { - match value { - Ok(v) => { - if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { - client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; - } - else { - //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose - // send the incoming text without context back to the sender - Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await - } - } - }, - Err(e) => { - error!("Broker Websocket error on read {:?}", e); - // Time to reconnect Thunder with existing subscription - break; - } - } - } - } - } + Self::process_new_req(&self_clone, r, url_clone, callback_clone.clone()).await; } }); } @@ -541,7 +539,7 @@ mod tests { thunder_async_client: Some(client), broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), - use_thunderbroker: true, + use_thunder_async: true, }; let response = json!({ diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 6e41ab823..34c14e159 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -217,7 +217,7 @@ pub struct ThunderClient { pub thunder_async_client: Option, pub broker_subscriptions: Option>>, pub broker_callbacks: Option>>, - pub use_thunderbroker: bool, + pub use_thunder_async: bool, } #[derive(Debug, Serialize, Deserialize)] @@ -245,7 +245,7 @@ impl ThunderClient { #[async_trait] impl DeviceOperator for ThunderClient { async fn call(&self, request: DeviceCallRequest) -> DeviceResponseMessage { - if !self.use_thunderbroker { + if !self.use_thunder_async { let (tx, rx) = oneshot::channel::(); let message = ThunderMessage::ThunderCallMessage(ThunderCallMessage { method: request.method, @@ -271,7 +271,7 @@ impl DeviceOperator for ThunderClient { request: DeviceSubscribeRequest, handler: mpsc::Sender, ) -> DeviceResponseMessage { - if !self.use_thunderbroker { + if !self.use_thunder_async { let (tx, rx) = oneshot::channel::(); let message = ThunderSubscribeMessage { module: request.module, @@ -302,7 +302,7 @@ impl DeviceOperator for ThunderClient { } async fn unsubscribe(&self, request: DeviceUnsubscribeRequest) { - if !self.use_thunderbroker { + if !self.use_thunder_async { let message = ThunderUnsubscribeMessage { module: request.module, event_name: request.event_name, @@ -732,7 +732,7 @@ impl ThunderClientBuilder { thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, - use_thunderbroker: false, + use_thunder_async: false, }) } @@ -791,9 +791,9 @@ impl ThunderClientBuilder { pool_tx: Option>, thunder_connection_state: Option>, existing_client: Option, - use_thndrbroker: bool, + use_thunderasync_client: bool, ) -> Result { - if !use_thndrbroker { + if !use_thunderasync_client { Self::start_thunderpool_client( url, plugin_manager_tx, @@ -818,7 +818,7 @@ impl ThunderClientBuilder { thunder_async_client: Some(client), broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), - use_thunderbroker: true, + use_thunder_async: true, }; ThunderClientManager::start( @@ -842,7 +842,7 @@ impl ThunderClientBuilder { thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, - use_thunderbroker: false, + use_thunder_async: false, } } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 2d5ab619e..9470d31b9 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -164,7 +164,7 @@ impl ThunderClientPool { thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, - use_thunderbroker: false, + use_thunder_async: false, }) } 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 d16d6cd66..d04c6f9ce 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -1135,7 +1135,7 @@ pub mod tests { broker_callbacks: None, broker_subscriptions: None, thunder_async_client: None, - use_thunderbroker: false, + use_thunder_async: false, }; let mut sessions: HashMap = HashMap::new(); sessions.insert("asdf".to_string(), operation.clone()); @@ -1172,7 +1172,7 @@ pub mod tests { broker_callbacks: None, broker_subscriptions: None, thunder_async_client: None, - use_thunderbroker: false, + use_thunder_async: false, }; let mut sessions: HashMap = HashMap::new(); sessions.insert("asdf".to_string(), operation.clone()); 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 c639e448d..eac9c9c6b 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -176,7 +176,7 @@ impl MockThunderController { thunder_async_client: None, broker_subscriptions: None, broker_callbacks: None, - use_thunderbroker: false, + use_thunder_async: false, }; let (s, r) = unbounded(); From a274ac71849d3d3637b4a2ae991083808b2c5d42 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 17 Jan 2025 11:11:43 +0530 Subject: [PATCH 35/51] fix: review comment fixed. --- core/main/src/broker/endpoint_broker.rs | 16 ++++++++++++---- .../thunder/thunder_plugins_status_mgr.rs | 11 ++++++----- .../src/broker/thunder/user_data_migrator.rs | 19 ++++++++++--------- core/sdk/src/utils/rpc_utils.rs | 17 ----------------- .../src/client/thunder_async_client.rs | 9 +++------ ...thunder_async_client_plugins_status_mgr.rs | 2 +- device/thunder_ripple_sdk/src/utils.rs | 12 +++++++++++- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/core/main/src/broker/endpoint_broker.rs b/core/main/src/broker/endpoint_broker.rs index 071bdfe1a..cc0e0820c 100644 --- a/core/main/src/broker/endpoint_broker.rs +++ b/core/main/src/broker/endpoint_broker.rs @@ -30,13 +30,16 @@ use ripple_sdk::{ self, sync::mpsc::{self, Receiver, Sender}, }, - utils::{error::RippleError, rpc_utils::get_next_id}, + utils::error::RippleError, }; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::{ collections::HashMap, - sync::{Arc, RwLock}, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, RwLock, + }, }; use crate::{ @@ -201,7 +204,7 @@ impl Default for BrokerCallback { } } -// static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); +static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); impl BrokerCallback { pub async fn send_json_rpc_api_response(&self, response: JsonRpcApiResponse) { @@ -407,6 +410,11 @@ impl EndpointBrokerState { } } + pub fn get_next_id() -> u64 { + ATOMIC_ID.fetch_add(1, Ordering::Relaxed); + ATOMIC_ID.load(Ordering::Relaxed) + } + fn update_request( &self, rpc_request: &RpcRequest, @@ -414,7 +422,7 @@ impl EndpointBrokerState { extn_message: Option, workflow_callback: Option, ) -> (u64, BrokerRequest) { - let id = get_next_id(); + let id = Self::get_next_id(); let mut rpc_request_c = rpc_request.clone(); { let mut request_map = self.request_map.write().unwrap(); diff --git a/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs b/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs index 946d8ccbb..b11274278 100644 --- a/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs +++ b/core/main/src/broker/thunder/thunder_plugins_status_mgr.rs @@ -28,8 +28,9 @@ use ripple_sdk::{ use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::broker::endpoint_broker::{BrokerCallback, BrokerRequest, BrokerSender}; -use ripple_sdk::utils::rpc_utils::get_next_id; +use crate::broker::endpoint_broker::{ + BrokerCallback, BrokerRequest, BrokerSender, EndpointBrokerState, +}; // defautl timeout for plugin activation in seconds const DEFAULT_PLUGIN_ACTIVATION_TIMEOUT: i64 = 8; @@ -228,7 +229,7 @@ impl StatusManager { } pub fn generate_plugin_activation_request(&self, plugin_name: String) -> String { - let id = get_next_id(); + let id = EndpointBrokerState::get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ @@ -246,7 +247,7 @@ impl StatusManager { } pub fn generate_plugin_status_request(&self, plugin_name: String) -> String { - let id = get_next_id(); + let id = EndpointBrokerState::get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ @@ -261,7 +262,7 @@ impl StatusManager { } pub fn generate_state_change_subscribe_request(&self) -> String { - let id = get_next_id(); + let id = EndpointBrokerState::get_next_id(); let controller_call_sign = Self::get_controller_call_sign(); let request = json!({ diff --git a/core/main/src/broker/thunder/user_data_migrator.rs b/core/main/src/broker/thunder/user_data_migrator.rs index 1c042814c..4e05a0701 100644 --- a/core/main/src/broker/thunder/user_data_migrator.rs +++ b/core/main/src/broker/thunder/user_data_migrator.rs @@ -35,19 +35,20 @@ use ripple_sdk::{ }, time::{timeout, Duration}, }, - utils::{error::RippleError, rpc_utils::get_next_id}, + utils::error::RippleError, }; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use crate::broker::endpoint_broker::{self, BrokerCallback, BrokerOutput, BrokerRequest}; -use crate::broker::rules_engine::{Rule, RuleTransformType}; +use crate::broker::{ + endpoint_broker::{self, BrokerCallback, BrokerOutput, BrokerRequest, EndpointBrokerState}, + rules_engine::{Rule, RuleTransformType}, + thunder_broker::ThunderBroker, +}; use futures::stream::SplitSink; use futures_util::SinkExt; - -use crate::broker::thunder_broker::ThunderBroker; use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; // TBD get the storage dir from manifest or other Ripple config file @@ -280,7 +281,7 @@ impl UserDataMigrator { broker: &ThunderBroker, ws_tx: Arc, Message>>>, ) -> Result { - let request_id = get_next_id(); + let request_id = EndpointBrokerState::get_next_id(); let call_sign = "org.rdk.PersistentStore.1.".to_owned(); // Register custom callback to handle the response @@ -367,7 +368,7 @@ impl UserDataMigrator { ws_tx: Arc, Message>>>, params_json: &Value, ) -> Result<(), UserDataMigratorError> { - let request_id = get_next_id(); + let request_id = EndpointBrokerState::get_next_id(); let call_sign = "org.rdk.PersistentStore.1.".to_owned(); // Register custom callback to handle the response @@ -434,7 +435,7 @@ impl UserDataMigrator { ws_tx: Arc, Message>>>, request: &BrokerRequest, ) -> Result { - let request_id = get_next_id(); + let request_id = EndpointBrokerState::get_next_id(); // Register custom callback to handle the response broker @@ -526,7 +527,7 @@ impl UserDataMigrator { } }; - let request_id = get_next_id(); + let request_id = EndpointBrokerState::get_next_id(); // Register custom callback to handle the response broker diff --git a/core/sdk/src/utils/rpc_utils.rs b/core/sdk/src/utils/rpc_utils.rs index 31c91d39a..712945926 100644 --- a/core/sdk/src/utils/rpc_utils.rs +++ b/core/sdk/src/utils/rpc_utils.rs @@ -16,14 +16,6 @@ // use jsonrpsee::core::Error; -use std::sync::atomic::{AtomicU64, Ordering}; - -static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); - -pub fn get_next_id() -> u64 { - ATOMIC_ID.fetch_add(1, Ordering::Relaxed); - ATOMIC_ID.load(Ordering::Relaxed) -} pub fn rpc_err(msg: impl Into) -> Error { Error::Custom(msg.into()) @@ -38,12 +30,3 @@ pub fn extract_tcp_port(url: &str) -> Result { Err(Error::Custom("Invalid URL format".to_string())) } } -// pub fn extract_tcp_port(url: &str) -> String { -// let url_split: Vec<&str> = url.split("://").collect(); -// if let Some(domain) = url_split.get(1) { -// let domain_split: Vec<&str> = domain.split('/').collect(); -// domain_split.first().unwrap().to_string() -// } else { -// url.to_owned() -// } -// } diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 6ea07a5e1..df5b64c6d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -15,9 +15,8 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::time::Duration; - use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; +use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; use ripple_sdk::api::device::device_operator::DeviceResponseMessage; @@ -27,12 +26,10 @@ use ripple_sdk::{ }, log::{debug, error, info}, tokio::{self, net::TcpStream, sync::mpsc::Receiver}, - utils::{ - error::RippleError, - rpc_utils::{extract_tcp_port, get_next_id}, - }, + utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; use serde_json::json; +use std::time::Duration; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; #[derive(Clone, Debug)] diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs index 70dc4ffa4..c7b33b49d 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs @@ -29,7 +29,7 @@ use ripple_sdk::{ }; use super::thunder_async_client::{ThunderAsyncRequest, ThunderAsyncResponse}; -use ripple_sdk::utils::rpc_utils::get_next_id; +use crate::utils::get_next_id; use serde::{Deserialize, Serialize}; use serde_json::json; diff --git a/device/thunder_ripple_sdk/src/utils.rs b/device/thunder_ripple_sdk/src/utils.rs index a9d38a7ef..e5de2aef4 100644 --- a/device/thunder_ripple_sdk/src/utils.rs +++ b/device/thunder_ripple_sdk/src/utils.rs @@ -15,7 +15,10 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::atomic::{AtomicU64, Ordering}, +}; use jsonrpsee::core::Error; use ripple_sdk::{ @@ -109,3 +112,10 @@ pub fn get_error_value(error: &Error) -> Value { } Value::Null } + +static ATOMIC_ID: AtomicU64 = AtomicU64::new(0); + +pub fn get_next_id() -> u64 { + ATOMIC_ID.fetch_add(1, Ordering::Relaxed); + ATOMIC_ID.load(Ordering::Relaxed) +} From 543c5ac261a07dba369b0277656481b29f8f6c49 Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Fri, 17 Jan 2025 12:42:51 -0500 Subject: [PATCH 36/51] Fixed status manager repsonse handling. --- .../thunder_ripple_sdk/src/client/thunder_async_client.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index df5b64c6d..c34950816 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -251,8 +251,16 @@ impl ThunderAsyncClient { match value { Ok(v) => { if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + // + // // send the incoming text without context back to the sender + // Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { + self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; + } else { // send the incoming text without context back to the sender Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + } + // } }, Err(e) => { From 586929633d974d508e784c7177adc6d3c0933239 Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Fri, 17 Jan 2025 12:45:32 -0500 Subject: [PATCH 37/51] Removed debug --- device/thunder_ripple_sdk/src/client/thunder_async_client.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index c34950816..10f26c244 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -251,16 +251,12 @@ impl ThunderAsyncClient { match value { Ok(v) => { if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - // - // // send the incoming text without context back to the sender - // Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; } else { // send the incoming text without context back to the sender Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await } - // } }, Err(e) => { From aa9129fd3d1fd01118d82f1434381a6129cabafc Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 21 Jan 2025 15:51:07 +0530 Subject: [PATCH 38/51] chore: renaming done for thunder async related variables structs for readability --- .../src/client/thunder_async_client.rs | 64 +++++++++---------- ...thunder_async_client_plugins_status_mgr.rs | 40 ++++++------ .../src/client/thunder_client.rs | 48 ++++++++------ .../src/client/thunder_client_pool.rs | 4 +- .../src/processors/thunder_package_manager.rs | 8 +-- .../src/tests/mock_thunder_controller.rs | 4 +- 6 files changed, 88 insertions(+), 80 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 10f26c244..15b21b5ac 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -15,7 +15,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender, StatusManager}; +use super::thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender, StatusManager}; use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; @@ -35,8 +35,8 @@ use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; #[derive(Clone, Debug)] pub struct ThunderAsyncClient { status_manager: StatusManager, - sender: BrokerSender, - callback: BrokerCallback, + sender: AsyncSender, + callback: AsyncCallback, } #[derive(Clone, Debug)] @@ -101,11 +101,11 @@ impl ThunderAsyncResponse { } impl ThunderAsyncClient { - pub fn get_sender(&self) -> BrokerSender { + pub fn get_sender(&self) -> AsyncSender { self.sender.clone() } - pub fn get_callback(&self) -> BrokerCallback { + pub fn get_callback(&self) -> AsyncCallback { self.callback.clone() } async fn create_ws( @@ -114,7 +114,7 @@ impl ThunderAsyncClient { SplitSink, Message>, SplitStream>, ) { - info!("Broker Endpoint url {}", endpoint); + info!("Thunder_async_client Endpoint url {}", endpoint); let port = extract_tcp_port(endpoint); let tcp_port = port.unwrap(); let mut index = 0; @@ -130,7 +130,7 @@ impl ThunderAsyncClient { } if (index % 10).eq(&0) { error!( - "Broker with {} failed with retry for last {} secs in {}", + "Thunder_async_client with {} failed with retry for last {} secs in {}", endpoint, index, tcp_port ); } @@ -155,7 +155,7 @@ impl ThunderAsyncClient { None => { // If the plugin status is not available, add the request to the pending list self.status_manager - .add_broker_request_to_pending_list(callsign.clone(), request.clone()); + .add_async_client_request_to_pending_list(callsign.clone(), request.clone()); // Generate a request to check the plugin status and add it to the requests list let request = self .status_manager @@ -180,7 +180,7 @@ impl ThunderAsyncClient { // If the plugin is not activated, add the request to the pending list and generate an activation request if !status.state.is_activated() { self.status_manager - .add_broker_request_to_pending_list(callsign.clone(), request.clone()); + .add_async_client_request_to_pending_list(callsign.clone(), request.clone()); let request = self .status_manager .generate_plugin_activation_request(callsign.clone()); @@ -227,7 +227,7 @@ impl ThunderAsyncClient { Ok(requests) } - pub fn new(callback: BrokerCallback, sender: BrokerSender) -> Self { + pub fn new(callback: AsyncCallback, sender: AsyncSender) -> Self { Self { status_manager: StatusManager::new(), sender, @@ -235,7 +235,7 @@ impl ThunderAsyncClient { } } - pub async fn process_new_req(&self, request: String, url: String, callback: BrokerCallback) { + pub async fn process_new_req(&self, request: String, url: String, callback: AsyncCallback) { let (mut new_wtx, mut new_wrx) = Self::create_ws(&url).await; let _feed = new_wtx .feed(tokio_tungstenite::tungstenite::Message::Text(request)) @@ -274,7 +274,7 @@ impl ThunderAsyncClient { ) -> Receiver { let callback = self.callback.clone(); let (mut ws_tx, mut ws_rx) = Self::create_ws(url).await; - // send the first request to the broker. This is the controller statechange subscription request + // send the controller statechange subscription request let status_request = self .status_manager .generate_state_change_subscribe_request(); @@ -307,7 +307,7 @@ impl ThunderAsyncClient { } }, Err(e) => { - error!("Broker Websocket error on read {:?}", e); + error!("Thunder_async_client Websocket error on read {:?}", e); break; } } @@ -349,9 +349,9 @@ impl ThunderAsyncClient { tr } - /// Default handler method for the broker to remove the context and send it back to the + /// Default handler method for the thunder async client to remove the context and send it back to the /// client for consumption - async fn handle_jsonrpc_response(result: &[u8], callback: BrokerCallback) { + async fn handle_jsonrpc_response(result: &[u8], callback: AsyncCallback) { if let Ok(message) = serde_json::from_slice::(result) { callback .send(ThunderAsyncResponse::new_response(message)) @@ -372,10 +372,8 @@ impl ThunderAsyncClient { mod tests { use super::*; use crate::client::thunder_client::ThunderClient; - //use crate::client::thunder_client_pool::tests::Uuid; use ripple_sdk::api::device::device_operator::DeviceCallRequest; use ripple_sdk::api::gateway::rpc_gateway_api::JsonRpcApiResponse; - //use ripple_sdk::async_channel::Recv; use ripple_sdk::utils::error::RippleError; use ripple_sdk::uuid::Uuid; use std::collections::HashMap; @@ -466,10 +464,10 @@ mod tests { #[tokio::test] async fn test_thunder_async_client_prepare_request() { let (resp_tx, _resp_rx) = mpsc::channel(10); - let callback = BrokerCallback { sender: resp_tx }; - let (broker_tx, _broker_rx) = mpsc::channel(10); - let broker_sender = BrokerSender { sender: broker_tx }; - let client = ThunderAsyncClient::new(callback, broker_sender); + let callback = AsyncCallback { sender: resp_tx }; + let (async_tx, _async_rx) = mpsc::channel(10); + let async_sender = AsyncSender { sender: async_tx }; + let client = ThunderAsyncClient::new(callback, async_sender); let callrequest = DeviceCallRequest { method: "org.rdk.System.1.getSerialNumber".to_string(), @@ -485,10 +483,10 @@ mod tests { #[tokio::test] async fn test_thunder_async_client_send() { let (resp_tx, _resp_rx) = mpsc::channel(10); - let callback = BrokerCallback { sender: resp_tx }; - let (broker_tx, mut broker_rx) = mpsc::channel(10); - let broker_sender = BrokerSender { sender: broker_tx }; - let client = ThunderAsyncClient::new(callback, broker_sender); + let callback = AsyncCallback { sender: resp_tx }; + let (async_tx, mut async_rx) = mpsc::channel(10); + let async_sender = AsyncSender { sender: async_tx }; + let client = ThunderAsyncClient::new(callback, async_sender); let callrequest = DeviceCallRequest { method: "org.rdk.System.1.getSerialNumber".to_string(), @@ -498,14 +496,14 @@ mod tests { let request = DeviceChannelRequest::Call(callrequest); let async_request = ThunderAsyncRequest::new(request); client.send(async_request.clone()).await; - let received = broker_rx.recv().await; + let received = async_rx.recv().await; assert_eq!(received.unwrap().id, async_request.id); } #[tokio::test] async fn test_thunder_async_client_handle_jsonrpc_response() { let (resp_tx, mut resp_rx) = mpsc::channel(10); - let callback = BrokerCallback { sender: resp_tx }; + let callback = AsyncCallback { sender: resp_tx }; let response = JsonRpcApiResponse { jsonrpc: "2.0".to_string(), id: Some(6), @@ -526,10 +524,10 @@ mod tests { #[tokio::test] async fn test_thunder_async_client_start() { let (resp_tx, mut resp_rx) = mpsc::channel(10); - let callback = BrokerCallback { sender: resp_tx }; - let (broker_tx, _broker_rx) = mpsc::channel(10); - let broker_sender = BrokerSender { sender: broker_tx }; - let client = ThunderAsyncClient::new(callback.clone(), broker_sender); + let callback = AsyncCallback { sender: resp_tx }; + let (async_tx, _async_rx) = mpsc::channel(10); + let async_sender = AsyncSender { sender: async_tx }; + let client = ThunderAsyncClient::new(callback.clone(), async_sender); let _thunder_client = ThunderClient { sender: None, @@ -538,8 +536,8 @@ mod tests { plugin_manager_tx: None, subscriptions: None, thunder_async_client: Some(client), - broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), - broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), + thunder_async_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), + thunder_async_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunder_async: true, }; diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs index c7b33b49d..263026bf6 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client_plugins_status_mgr.rs @@ -34,11 +34,11 @@ use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Clone, Debug)] -pub struct BrokerSender { +pub struct AsyncSender { pub sender: Sender, } -impl BrokerSender { +impl AsyncSender { // Method to send the request to the underlying broker for handling. pub async fn send(&self, request: ThunderAsyncRequest) -> RippleResponse { if let Err(e) = self.sender.send(request).await { @@ -53,11 +53,11 @@ impl BrokerSender { /// BrokerCallback will be used by the communication broker to send the firebolt response /// back to the gateway for client consumption #[derive(Clone, Debug)] -pub struct BrokerCallback { +pub struct AsyncCallback { pub sender: Sender, } -impl BrokerCallback { +impl AsyncCallback { pub async fn send(&self, response: ThunderAsyncResponse) { if (self.sender.send(response).await).is_err() { error!("error returning callback for request") @@ -197,7 +197,7 @@ impl StatusManager { } } - pub fn add_broker_request_to_pending_list( + pub fn add_async_client_request_to_pending_list( &self, plugin_name: String, request: ThunderAsyncRequest, @@ -324,8 +324,8 @@ impl StatusManager { pub async fn is_controller_response( &self, - sender: BrokerSender, - callback: BrokerCallback, + sender: AsyncSender, + callback: AsyncCallback, result: &[u8], ) -> bool { let data = match serde_json::from_slice::(result) { @@ -380,8 +380,8 @@ impl StatusManager { } async fn on_activate_response( &self, - sender: BrokerSender, - callback: BrokerCallback, + sender: AsyncSender, + callback: AsyncCallback, data: &JsonRpcApiResponse, request: &str, ) { @@ -418,8 +418,8 @@ impl StatusManager { async fn on_status_response( &self, - sender: BrokerSender, - callback: BrokerCallback, + sender: AsyncSender, + callback: AsyncCallback, data: &JsonRpcApiResponse, request: &str, ) { @@ -470,7 +470,7 @@ impl StatusManager { async fn on_thunder_error_response( &self, - callback: BrokerCallback, + callback: AsyncCallback, data: &JsonRpcApiResponse, plugin_name: &String, ) { @@ -511,8 +511,8 @@ impl StatusManager { pub async fn handle_controller_response( &self, - sender: BrokerSender, - callback: BrokerCallback, + sender: AsyncSender, + callback: AsyncCallback, result: &[u8], ) { let data = match serde_json::from_slice::(result) { @@ -548,7 +548,7 @@ impl StatusManager { } } -impl BrokerCallback { +impl AsyncCallback { /// Default method used for sending errors via the BrokerCallback pub async fn send_error(&self, request: ThunderAsyncRequest, error: RippleError) { let response = ThunderAsyncResponse { @@ -579,10 +579,10 @@ mod tests { async fn test_on_activate_response() { let status_manager = StatusManager::new(); let (tx, _tr) = mpsc::channel(10); - let broker = BrokerSender { sender: tx }; + let broker = AsyncSender { sender: tx }; let (tx_1, _tr_1) = channel(2); - let callback = BrokerCallback { sender: tx_1 }; + let callback = AsyncCallback { sender: tx_1 }; let data = JsonRpcApiResponse { id: Some(1), @@ -604,10 +604,10 @@ mod tests { async fn test_on_status_response() { let status_manager = StatusManager::new(); let (tx, _tr) = mpsc::channel(10); - let broker = BrokerSender { sender: tx }; + let broker = AsyncSender { sender: tx }; let (tx_1, _tr_1) = channel(2); - let callback = BrokerCallback { sender: tx_1 }; + let callback = AsyncCallback { sender: tx_1 }; let data = JsonRpcApiResponse { id: Some(1), @@ -630,7 +630,7 @@ mod tests { let status_manager = StatusManager::new(); let (tx_1, _tr_1) = channel(2); - let callback = BrokerCallback { sender: tx_1 }; + let callback = AsyncCallback { sender: tx_1 }; let data = JsonRpcApiResponse { id: Some(1), diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 34c14e159..42d803555 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -16,7 +16,7 @@ // use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, ThunderAsyncResponse}; -use super::thunder_async_client_plugins_status_mgr::{BrokerCallback, BrokerSender}; +use super::thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender}; use super::thunder_client_pool::ThunderPoolCommand; use super::{ jsonrpc_method_locator::JsonRpcMethodLocator, @@ -81,8 +81,8 @@ impl ThunderClientManager { tokio::spawn(async move { while let Some(response) = response_tr.recv().await { if let Some(id) = response.get_id() { - if let Some(broker_callbacks) = client.clone().broker_callbacks { - let mut callbacks = broker_callbacks.write().unwrap(); + if let Some(thunder_async_callbacks) = client.clone().thunder_async_callbacks { + let mut callbacks = thunder_async_callbacks.write().unwrap(); if let Some(Some(callback)) = callbacks.remove(&id) { if let Some(resp) = response.get_device_resp_msg(None) { oneshot_send_and_log(callback, resp, "ThunderResponse"); @@ -90,7 +90,7 @@ impl ThunderClientManager { } } } else if let Some(event_name) = response.get_method() { - if let Some(broker_subs) = client.clone().broker_subscriptions { + if let Some(broker_subs) = client.clone().thunder_async_subscriptions { let subs = { let mut br_subs = broker_subs.write().unwrap(); br_subs.get_mut(&event_name).cloned() @@ -215,8 +215,8 @@ pub struct ThunderClient { pub plugin_manager_tx: Option>, pub subscriptions: Option>>>, pub thunder_async_client: Option, - pub broker_subscriptions: Option>>, - pub broker_callbacks: Option>>, + pub thunder_async_subscriptions: Option>>, + pub thunder_async_callbacks: Option>>, pub use_thunder_async: bool, } @@ -560,7 +560,12 @@ impl ThunderClient { request: &ThunderAsyncRequest, dev_resp_callback: Sender, ) { - let mut callbacks = self.broker_callbacks.as_ref().unwrap().write().unwrap(); + let mut callbacks = self + .thunder_async_callbacks + .as_ref() + .unwrap() + .write() + .unwrap(); callbacks.insert(request.id, Some(dev_resp_callback)); } @@ -570,13 +575,18 @@ impl ThunderClient { request: &DeviceSubscribeRequest, handler: MpscSender, ) -> Option { - let mut broker_subscriptions = self.broker_subscriptions.as_ref().unwrap().write().unwrap(); + let mut thunder_async_subscriptions = self + .thunder_async_subscriptions + .as_ref() + .unwrap() + .write() + .unwrap(); // Create a key for the subscription based on the event name let key = format!("client.events.{}", request.event_name); // Check if there are existing subscriptions for the given key - if let Some(subs) = broker_subscriptions.get_mut(&key) { + if let Some(subs) = thunder_async_subscriptions.get_mut(&key) { // If a subscription exists, add the handler to the list of handlers subs.handlers.push(handler); None @@ -591,8 +601,8 @@ impl ThunderClient { handlers: vec![handler], }; - // Insert the new subscription into the broker_subscriptions map - broker_subscriptions.insert(key, dev_resp_sub); + // Insert the new subscription into the thunder_async_subscriptions map + thunder_async_subscriptions.insert(key, dev_resp_sub); Some(async_request) } } @@ -730,8 +740,8 @@ impl ThunderClientBuilder { plugin_manager_tx: pmtx_c, subscriptions: Some(subscriptions), thunder_async_client: None, - broker_subscriptions: None, - broker_callbacks: None, + thunder_async_subscriptions: None, + thunder_async_callbacks: None, use_thunder_async: false, }) } @@ -804,9 +814,9 @@ impl ThunderClientBuilder { .await } else { let (resp_tx, resp_rx) = mpsc::channel(10); - let callback = BrokerCallback { sender: resp_tx }; + let callback = AsyncCallback { sender: resp_tx }; let (broker_tx, broker_rx) = mpsc::channel(10); - let broker_sender = BrokerSender { sender: broker_tx }; + let broker_sender = AsyncSender { sender: broker_tx }; let client = ThunderAsyncClient::new(callback, broker_sender); let thunder_client = ThunderClient { @@ -816,8 +826,8 @@ impl ThunderClientBuilder { plugin_manager_tx: None, subscriptions: None, thunder_async_client: Some(client), - broker_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), - broker_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), + thunder_async_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), + thunder_async_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), use_thunder_async: true, }; @@ -840,8 +850,8 @@ impl ThunderClientBuilder { plugin_manager_tx: None, subscriptions: None, thunder_async_client: None, - broker_subscriptions: None, - broker_callbacks: None, + thunder_async_subscriptions: None, + thunder_async_callbacks: None, use_thunder_async: false, } } diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 9470d31b9..59de5810a 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -162,8 +162,8 @@ impl ThunderClientPool { plugin_manager_tx: pmtx_c, subscriptions: None, thunder_async_client: None, - broker_subscriptions: None, - broker_callbacks: None, + thunder_async_subscriptions: None, + thunder_async_callbacks: None, use_thunder_async: false, }) } 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 d04c6f9ce..0bdc12ad8 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -1132,8 +1132,8 @@ pub mod tests { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - broker_callbacks: None, - broker_subscriptions: None, + thunder_async_callbacks: None, + thunder_async_subscriptions: None, thunder_async_client: None, use_thunder_async: false, }; @@ -1169,8 +1169,8 @@ pub mod tests { id: Uuid::new_v4(), plugin_manager_tx: None, subscriptions: None, - broker_callbacks: None, - broker_subscriptions: None, + thunder_async_callbacks: None, + thunder_async_subscriptions: None, thunder_async_client: None, use_thunder_async: false, }; 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 eac9c9c6b..ef8921ed7 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -174,8 +174,8 @@ impl MockThunderController { plugin_manager_tx: None, subscriptions: None, thunder_async_client: None, - broker_subscriptions: None, - broker_callbacks: None, + thunder_async_subscriptions: None, + thunder_async_callbacks: None, use_thunder_async: false, }; From bdf2afb6e73f2e35db6dd021ad7ded267277ad85 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Tue, 21 Jan 2025 22:35:59 +0530 Subject: [PATCH 39/51] fix: device_operator file directory changed.moved into thunder_ripple_sdk --- core/sdk/src/api/device/mod.rs | 1 - device/thunder_ripple_sdk/Cargo.toml | 2 +- .../src/client}/device_operator.rs | 11 +++---- .../src/client/plugin_manager.rs | 23 ++++++------- .../src/client/thunder_async_client.rs | 13 ++++---- .../src/client/thunder_client.rs | 10 +++--- .../src/client/thunder_client_pool.rs | 20 ++++++------ .../src/events/thunder_event_processor.rs | 6 ++-- device/thunder_ripple_sdk/src/lib.rs | 1 + .../src/processors/thunder_analytics.rs | 16 ++++++---- .../src/processors/thunder_browser.rs | 15 +++++---- .../src/processors/thunder_device_info.rs | 13 +++++--- .../src/processors/thunder_package_manager.rs | 10 ++++-- .../processors/thunder_persistent_store.rs | 13 ++++---- .../src/processors/thunder_remote.rs | 18 +++++------ .../src/processors/thunder_rfc.rs | 13 +++++--- .../src/processors/thunder_telemetry.rs | 13 +++++--- .../src/processors/thunder_wifi.rs | 32 ++++++++++--------- .../src/processors/thunder_window_manager.rs | 16 +++++----- .../contracts/thunder_controller_pacts.rs | 9 +++--- .../src/tests/mock_thunder_controller.rs | 2 +- .../thunder_ripple_sdk/src/thunder_state.rs | 9 +++--- device/thunder_ripple_sdk/src/utils.rs | 6 ++-- 23 files changed, 148 insertions(+), 124 deletions(-) rename {core/sdk/src/api/device => device/thunder_ripple_sdk/src/client}/device_operator.rs (97%) diff --git a/core/sdk/src/api/device/mod.rs b/core/sdk/src/api/device/mod.rs index 94ca527b2..afd70c419 100644 --- a/core/sdk/src/api/device/mod.rs +++ b/core/sdk/src/api/device/mod.rs @@ -21,7 +21,6 @@ pub mod device_apps; pub mod device_browser; pub mod device_events; pub mod device_info_request; -pub mod device_operator; pub mod device_peristence; pub mod device_request; pub mod device_user_grants_data; diff --git a/device/thunder_ripple_sdk/Cargo.toml b/device/thunder_ripple_sdk/Cargo.toml index ee11bd794..f08d3e926 100644 --- a/device/thunder_ripple_sdk/Cargo.toml +++ b/device/thunder_ripple_sdk/Cargo.toml @@ -64,4 +64,4 @@ futures-util = { version = "0.3.28", features = ["sink", "std"], default-feature [dev-dependencies] ripple_sdk = { path = "../../core/sdk", features = ["tdk"] } - +rstest = "0.18.0" diff --git a/core/sdk/src/api/device/device_operator.rs b/device/thunder_ripple_sdk/src/client/device_operator.rs similarity index 97% rename from core/sdk/src/api/device/device_operator.rs rename to device/thunder_ripple_sdk/src/client/device_operator.rs index fdbd597d8..00475a652 100644 --- a/core/sdk/src/api/device/device_operator.rs +++ b/device/thunder_ripple_sdk/src/client/device_operator.rs @@ -14,13 +14,12 @@ // // SPDX-License-Identifier: Apache-2.0 // - -use crate::api::gateway::rpc_gateway_api::JsonRpcApiResponse; -use async_trait::async_trait; -use log::error; +use ripple_sdk::{ + api::gateway::rpc_gateway_api::JsonRpcApiResponse, async_trait::async_trait, log::error, + tokio::sync::mpsc, +}; use serde::{Deserialize, Serialize}; use serde_json::Value; -use tokio::sync::mpsc; pub const DEFAULT_DEVICE_OPERATION_TIMEOUT_SECS: u64 = 5; @@ -42,7 +41,7 @@ pub trait DeviceOperator: Clone { #[derive(Debug, Clone)] pub struct DeviceResponseSubscription { pub sub_id: Option, - pub handlers: Vec>, + pub handlers: Vec>, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/device/thunder_ripple_sdk/src/client/plugin_manager.rs b/device/thunder_ripple_sdk/src/client/plugin_manager.rs index 0e46d4a76..75d652cc1 100644 --- a/device/thunder_ripple_sdk/src/client/plugin_manager.rs +++ b/device/thunder_ripple_sdk/src/client/plugin_manager.rs @@ -15,25 +15,26 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::{HashMap, HashSet}; -use std::time::Duration; - use ripple_sdk::log::info; use ripple_sdk::tokio; +use ripple_sdk::{log::error, serde_json}; use ripple_sdk::{ - api::device::device_operator::{DeviceCallRequest, DeviceSubscribeRequest}, - log::error, - serde_json, -}; -use ripple_sdk::{ - api::device::device_operator::{DeviceChannelParams, DeviceOperator, DeviceResponseMessage}, tokio::sync::{mpsc, oneshot}, utils::channel_utils::{mpsc_send_and_log, oneshot_send_and_log}, }; use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; +use std::time::Duration; -use super::thunder_plugin::ThunderPlugin::Controller; -use super::{thunder_client::ThunderClient, thunder_plugin::ThunderPlugin}; +use super::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + DeviceSubscribeRequest, + }, + thunder_client::ThunderClient, + thunder_plugin::ThunderPlugin, + thunder_plugin::ThunderPlugin::Controller, +}; pub struct ActivationSubscriber { pub callsign: String, diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 15b21b5ac..e8438c85f 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -15,15 +15,15 @@ // SPDX-License-Identifier: Apache-2.0 // -use super::thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender, StatusManager}; +use super::{ + device_operator::{DeviceChannelRequest, DeviceResponseMessage}, + thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender, StatusManager}, +}; use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; -use ripple_sdk::api::device::device_operator::DeviceResponseMessage; use ripple_sdk::{ - api::{ - device::device_operator::DeviceChannelRequest, gateway::rpc_gateway_api::JsonRpcApiResponse, - }, + api::gateway::rpc_gateway_api::JsonRpcApiResponse, log::{debug, error, info}, tokio::{self, net::TcpStream, sync::mpsc::Receiver}, utils::{error::RippleError, rpc_utils::extract_tcp_port}, @@ -371,8 +371,7 @@ impl ThunderAsyncClient { #[cfg(test)] mod tests { use super::*; - use crate::client::thunder_client::ThunderClient; - use ripple_sdk::api::device::device_operator::DeviceCallRequest; + use crate::client::{device_operator::DeviceCallRequest, thunder_client::ThunderClient}; use ripple_sdk::api::gateway::rpc_gateway_api::JsonRpcApiResponse; use ripple_sdk::utils::error::RippleError; use ripple_sdk::uuid::Uuid; diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 42d803555..9ba77cd67 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -19,6 +19,11 @@ use super::thunder_async_client::{ThunderAsyncClient, ThunderAsyncRequest, Thund use super::thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender}; use super::thunder_client_pool::ThunderPoolCommand; use super::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceChannelRequest, DeviceOperator, + DeviceResponseMessage, DeviceResponseSubscription, DeviceSubscribeRequest, + DeviceUnsubscribeRequest, + }, jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginActivatedResult, PluginManagerCommand}, }; @@ -30,11 +35,6 @@ use jsonrpsee::types::ParamsSer; use jsonrpsee::ws_client::WsClientBuilder; use regex::Regex; use ripple_sdk::{ - api::device::device_operator::{ - DeviceCallRequest, DeviceChannelParams, DeviceChannelRequest, DeviceOperator, - DeviceResponseMessage, DeviceResponseSubscription, DeviceSubscribeRequest, - DeviceUnsubscribeRequest, - }, log::{error, info, warn}, serde_json::{self, json, Value}, tokio, diff --git a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs index 59de5810a..7da634843 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client_pool.rs @@ -20,9 +20,11 @@ use std::sync::{ Arc, }; -use crate::{client::thunder_client::ThunderClientBuilder, thunder_state::ThunderConnectionState}; +use crate::{ + client::{device_operator::DeviceResponseMessage, thunder_client::ThunderClientBuilder}, + thunder_state::ThunderConnectionState, +}; use ripple_sdk::{ - api::device::device_operator::DeviceResponseMessage, log::{debug, error}, tokio::sync::{mpsc, oneshot}, utils::channel_utils::oneshot_send_and_log, @@ -190,19 +192,19 @@ impl ThunderClientPool { mod tests { use super::*; use crate::{ - client::plugin_manager::{PluginActivatedResult, PluginManagerCommand}, + client::{ + device_operator::{ + DeviceCallRequest, DeviceOperator, DeviceSubscribeRequest, DeviceUnsubscribeRequest, + }, + plugin_manager::{PluginActivatedResult, PluginManagerCommand}, + }, tests::thunder_client_pool_test_utility::{ CustomMethodHandler, MethodHandler, MockWebSocketServer, }, }; - use ripple_sdk::api::device::device_operator::DeviceUnsubscribeRequest; - use ripple_sdk::{ - api::device::device_operator::DeviceSubscribeRequest, - utils::channel_utils::oneshot_send_and_log, - }; use ripple_sdk::{ - api::device::device_operator::{DeviceCallRequest, DeviceOperator}, tokio::time::{sleep, Duration}, + utils::channel_utils::oneshot_send_and_log, }; use url::Url; 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 5d5b0588a..fcadbfa85 100644 --- a/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs +++ b/device/thunder_ripple_sdk/src/events/thunder_event_processor.rs @@ -27,7 +27,6 @@ use ripple_sdk::{ context::RippleContextUpdateRequest, device::{ device_events::{DeviceEvent, DeviceEventCallback}, - device_operator::DeviceSubscribeRequest, device_request::{ AudioProfile, InternetConnectionStatus, NetworkResponse, PowerState, SystemPowerState, VoiceGuidanceState, @@ -41,7 +40,10 @@ use ripple_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{thunder_state::ThunderState, utils::get_audio_profile_from_value}; +use crate::{ + client::device_operator::DeviceSubscribeRequest, thunder_state::ThunderState, + utils::get_audio_profile_from_value, +}; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] diff --git a/device/thunder_ripple_sdk/src/lib.rs b/device/thunder_ripple_sdk/src/lib.rs index 462f9dcdb..b2d2c00f4 100644 --- a/device/thunder_ripple_sdk/src/lib.rs +++ b/device/thunder_ripple_sdk/src/lib.rs @@ -16,6 +16,7 @@ // pub mod client { + pub mod device_operator; pub mod jsonrpc_method_locator; pub mod plugin_manager; pub mod thunder_async_client; diff --git a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs index 0bf919654..afc92582c 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_analytics.rs @@ -17,11 +17,7 @@ use ripple_sdk::{ api::{ - device::device_operator::{ - DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, - }, - firebolt::fb_metrics::BehavioralMetricsEvent, - observability::analytics::AnalyticsRequest, + firebolt::fb_metrics::BehavioralMetricsEvent, observability::analytics::AnalyticsRequest, }, async_trait::async_trait, extn::{ @@ -38,7 +34,15 @@ use ripple_sdk::{ utils::error::RippleError, }; -use crate::{client::thunder_plugin::ThunderPlugin, thunder_state::ThunderState}; +use crate::{ + client::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + }, + thunder_plugin::ThunderPlugin, + }, + thunder_state::ThunderState, +}; #[derive(Debug)] pub struct ThunderAnalyticsProcessor { diff --git a/device/thunder_ripple_sdk/src/processors/thunder_browser.rs b/device/thunder_ripple_sdk/src/processors/thunder_browser.rs index eba89f38c..814cf76b3 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_browser.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_browser.rs @@ -16,11 +16,8 @@ // use ripple_sdk::{ - api::device::{ - device_browser::{ - BrowserDestroyParams, BrowserLaunchParams, BrowserNameRequestParams, BrowserRequest, - }, - device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + api::device::device_browser::{ + BrowserDestroyParams, BrowserLaunchParams, BrowserNameRequestParams, BrowserRequest, }, async_trait::async_trait, extn::{ @@ -40,7 +37,13 @@ use ripple_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{client::thunder_plugin::ThunderPlugin, thunder_state::ThunderState}; +use crate::{ + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_plugin::ThunderPlugin, + }, + thunder_state::ThunderState, +}; #[derive(Debug)] pub struct ThunderBrowserRequestProcessor { 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 daad19614..220d8a53c 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_device_info.rs @@ -22,7 +22,11 @@ use std::{ }; use crate::{ - client::{thunder_client::ThunderClient, thunder_plugin::ThunderPlugin}, + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_client::ThunderClient, + thunder_plugin::ThunderPlugin, + }, ripple_sdk::{ api::device::{device_info_request::DeviceCapabilities, device_request::AudioProfile}, chrono::NaiveDateTime, @@ -37,7 +41,6 @@ use crate::{ api::{ device::{ device_info_request::{DeviceInfoRequest, DeviceResponse}, - device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, device_request::{ HDCPStatus, HdcpProfile, HdrProfile, NetworkResponse, NetworkState, NetworkType, Resolution, @@ -1658,7 +1661,6 @@ pub mod tests { use ripple_sdk::{ api::device::{ device_info_request::{DeviceInfoRequest, DeviceResponse, PlatformBuildInfo}, - device_operator::DeviceResponseMessage, device_request::DeviceRequest, }, extn::{ @@ -1674,7 +1676,10 @@ pub mod tests { use serde::{Deserialize, Serialize}; use crate::{ - client::{thunder_client::ThunderCallMessage, thunder_plugin::ThunderPlugin}, + client::{ + device_operator::DeviceResponseMessage, thunder_client::ThunderCallMessage, + thunder_plugin::ThunderPlugin, + }, processors::thunder_device_info::ThunderDeviceInfoRequestProcessor, tests::mock_thunder_controller::{CustomHandler, MockThunderController, ThunderHandlerFn}, }; 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 0bdc12ad8..d90fcedf7 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_package_manager.rs @@ -22,9 +22,14 @@ use std::{thread, time}; use crate::ripple_sdk::{self}; use crate::{ - client::thunder_plugin::ThunderPlugin, + client::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + DeviceSubscribeRequest, + }, + thunder_plugin::ThunderPlugin, + }, ripple_sdk::{ - api::device::device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, async_trait::async_trait, extn::{ client::extn_client::ExtnClient, @@ -41,7 +46,6 @@ use crate::{ use base64::{engine::general_purpose::STANDARD as base64, Engine}; use ripple_sdk::api::app_catalog::{AppCatalogRequest, AppOperationComplete, AppsUpdate}; use ripple_sdk::api::device::device_apps::DeviceAppMetadata; -use ripple_sdk::api::device::device_operator::{DeviceResponseMessage, DeviceSubscribeRequest}; use ripple_sdk::api::firebolt::fb_capabilities::FireboltPermissions; use ripple_sdk::api::firebolt::fb_metrics::{Timer, TimerType}; use ripple_sdk::api::observability::metrics_util::{ 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 cf0b1e3a8..532b1ee6a 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_persistent_store.rs @@ -16,14 +16,13 @@ // use crate::{ - client::thunder_plugin::ThunderPlugin, + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_plugin::ThunderPlugin, + }, ripple_sdk::{ - api::device::{ - device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, - device_peristence::{ - DeleteStorageProperty, DevicePersistenceRequest, GetStorageProperty, - SetStorageProperty, - }, + api::device::device_peristence::{ + DeleteStorageProperty, DevicePersistenceRequest, GetStorageProperty, SetStorageProperty, }, async_trait::async_trait, extn::{ diff --git a/device/thunder_ripple_sdk/src/processors/thunder_remote.rs b/device/thunder_ripple_sdk/src/processors/thunder_remote.rs index 357befc2a..c05faa69c 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_remote.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_remote.rs @@ -17,22 +17,20 @@ use crate::{ client::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + DeviceSubscribeRequest, DeviceUnsubscribeRequest, + }, thunder_client::ThunderClient, thunder_plugin::ThunderPlugin::{self, RemoteControl}, }, ripple_sdk::{ api::{ accessory::RemoteAccessoryResponse, - device::{ - device_accessory::{ - AccessoryDeviceListResponse, AccessoryDeviceResponse, AccessoryListRequest, - AccessoryPairRequest, AccessoryProtocol, AccessoryProtocolListType, - AccessoryType, RemoteAccessoryRequest, - }, - device_operator::{ - DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, - DeviceSubscribeRequest, DeviceUnsubscribeRequest, - }, + device::device_accessory::{ + AccessoryDeviceListResponse, AccessoryDeviceResponse, AccessoryListRequest, + AccessoryPairRequest, AccessoryProtocol, AccessoryProtocolListType, AccessoryType, + RemoteAccessoryRequest, }, }, async_trait::async_trait, diff --git a/device/thunder_ripple_sdk/src/processors/thunder_rfc.rs b/device/thunder_ripple_sdk/src/processors/thunder_rfc.rs index 48f9293d8..2d67d1a52 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_rfc.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_rfc.rs @@ -18,10 +18,7 @@ use std::collections::HashMap; use ripple_sdk::{ - api::{ - config::RfcRequest, - device::device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, - }, + api::config::RfcRequest, async_trait::async_trait, extn::{ client::{ @@ -39,7 +36,13 @@ use ripple_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{client::thunder_plugin::ThunderPlugin, thunder_state::ThunderState}; +use crate::{ + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_plugin::ThunderPlugin, + }, + thunder_state::ThunderState, +}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ThunderRFCResponse { diff --git a/device/thunder_ripple_sdk/src/processors/thunder_telemetry.rs b/device/thunder_ripple_sdk/src/processors/thunder_telemetry.rs index cce5c389f..dda24e5c6 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_telemetry.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_telemetry.rs @@ -16,10 +16,7 @@ // use ripple_sdk::{ - api::{ - device::device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, - firebolt::fb_telemetry::TelemetryPayload, - }, + api::firebolt::fb_telemetry::TelemetryPayload, async_trait::async_trait, extn::{ client::extn_processor::{ @@ -34,7 +31,13 @@ use ripple_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{client::thunder_plugin::ThunderPlugin, thunder_state::ThunderState}; +use crate::{ + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_plugin::ThunderPlugin, + }, + thunder_state::ThunderState, +}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] diff --git a/device/thunder_ripple_sdk/src/processors/thunder_wifi.rs b/device/thunder_ripple_sdk/src/processors/thunder_wifi.rs index c49fdc65b..3c267cb04 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_wifi.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_wifi.rs @@ -16,15 +16,25 @@ // use crate::{ - client::thunder_plugin::ThunderPlugin, + client::thunder_plugin::ThunderPlugin::Wifi, + ripple_sdk::{ + self, + api::device::device_wifi::WifiRequest, + extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider}, + }, +}; +use crate::{ + client::{ + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + DeviceSubscribeRequest, DeviceUnsubscribeRequest, + }, + thunder_plugin::ThunderPlugin, + }, ripple_sdk::{ api::{ - device::{ - device_operator::{ - DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, - DeviceSubscribeRequest, - }, - device_wifi::{AccessPoint, AccessPointList, AccessPointRequest, WifiSecurityMode}, + device::device_wifi::{ + AccessPoint, AccessPointList, AccessPointRequest, WifiSecurityMode, }, wifi::WifiResponse, }, @@ -42,14 +52,6 @@ use crate::{ }, thunder_state::ThunderState, }; -use crate::{ - client::thunder_plugin::ThunderPlugin::Wifi, - ripple_sdk::{ - self, - api::device::{device_operator::DeviceUnsubscribeRequest, device_wifi::WifiRequest}, - extn::extn_client_message::{ExtnPayload, ExtnPayloadProvider}, - }, -}; use serde::{Deserialize, Serialize}; use tokio::time::{self, timeout, Duration}; diff --git a/device/thunder_ripple_sdk/src/processors/thunder_window_manager.rs b/device/thunder_ripple_sdk/src/processors/thunder_window_manager.rs index 5178a6e9d..70047d2d0 100644 --- a/device/thunder_ripple_sdk/src/processors/thunder_window_manager.rs +++ b/device/thunder_ripple_sdk/src/processors/thunder_window_manager.rs @@ -16,13 +16,7 @@ // use crate::ripple_sdk::{ - api::{ - apps::Dimensions, - device::{ - device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, - device_window_manager::WindowManagerRequest, - }, - }, + api::{apps::Dimensions, device::device_window_manager::WindowManagerRequest}, async_trait::async_trait, extn::{ client::{ @@ -39,7 +33,13 @@ use crate::ripple_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{client::thunder_plugin::ThunderPlugin, thunder_state::ThunderState}; +use crate::{ + client::{ + device_operator::{DeviceCallRequest, DeviceChannelParams, DeviceOperator}, + thunder_plugin::ThunderPlugin, + }, + thunder_state::ThunderState, +}; #[derive(Debug)] pub struct ThunderWindowManagerRequestProcessor { 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 ac0069d17..d4736d38a 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,6 +1,10 @@ use crate::{ client::{ - plugin_manager::ThunderActivatePluginParams, thunder_client::ThunderClient, + device_operator::{ + DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, + }, + plugin_manager::ThunderActivatePluginParams, + thunder_client::ThunderClient, thunder_client_pool::ThunderClientPool, }, ripple_sdk::{ @@ -9,9 +13,6 @@ use crate::{ }, thunder_state::ThunderConnectionState, }; -use ripple_sdk::api::device::device_operator::{ - DeviceCallRequest, DeviceChannelParams, DeviceOperator, DeviceResponseMessage, -}; use crate::mock_websocket_server; use pact_consumer::mock_server::StartMockServerAsync; 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 ef8921ed7..6284888bb 100644 --- a/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs +++ b/device/thunder_ripple_sdk/src/tests/mock_thunder_controller.rs @@ -1,7 +1,6 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; use ripple_sdk::{ - api::device::device_operator::DeviceResponseMessage, async_channel::{unbounded, Receiver}, extn::{ffi::ffi_message::CExtnMessage, mock_extension_client::MockExtnClient}, serde_json, @@ -13,6 +12,7 @@ use serde_json::Value; use crate::{ client::{ + device_operator::DeviceResponseMessage, jsonrpc_method_locator::JsonRpcMethodLocator, plugin_manager::{PluginState, PluginStateChangeEvent, PluginStatus}, thunder_client::{ diff --git a/device/thunder_ripple_sdk/src/thunder_state.rs b/device/thunder_ripple_sdk/src/thunder_state.rs index 8388a504a..9efebc4f9 100644 --- a/device/thunder_ripple_sdk/src/thunder_state.rs +++ b/device/thunder_ripple_sdk/src/thunder_state.rs @@ -18,9 +18,6 @@ use std::sync::{Arc, RwLock}; use ripple_sdk::{ - api::device::device_operator::{ - DeviceOperator, DeviceResponseMessage, DeviceUnsubscribeRequest, - }, extn::{ client::extn_client::ExtnClient, extn_client_message::{ExtnMessage, ExtnPayloadProvider}, @@ -33,7 +30,11 @@ use ripple_sdk::{ use url::Url; use crate::{ - client::{plugin_manager::ThunderPluginBootParam, thunder_client::ThunderClient}, + client::{ + device_operator::{DeviceOperator, DeviceResponseMessage, DeviceUnsubscribeRequest}, + plugin_manager::ThunderPluginBootParam, + thunder_client::ThunderClient, + }, events::thunder_event_processor::{ThunderEventHandler, ThunderEventProcessor}, }; diff --git a/device/thunder_ripple_sdk/src/utils.rs b/device/thunder_ripple_sdk/src/utils.rs index e5de2aef4..449068645 100644 --- a/device/thunder_ripple_sdk/src/utils.rs +++ b/device/thunder_ripple_sdk/src/utils.rs @@ -20,11 +20,9 @@ use std::{ sync::atomic::{AtomicU64, Ordering}, }; +use crate::client::device_operator::DeviceResponseMessage; use jsonrpsee::core::Error; -use ripple_sdk::{ - api::device::{device_operator::DeviceResponseMessage, device_request::AudioProfile}, - serde_json::Value, -}; +use ripple_sdk::{api::device::device_request::AudioProfile, serde_json::Value}; use serde::Deserialize; pub fn get_audio_profile_from_value(value: Value) -> HashMap { From 3039eede824734d46723cc20fdeb01cf4b2ead80 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Thu, 23 Jan 2025 22:54:40 +0530 Subject: [PATCH 40/51] fix: added handling for notification receiving in thunder_async_client start fn. --- .../src/client/thunder_async_client.rs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index e8438c85f..1b8f79238 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -254,8 +254,9 @@ impl ThunderAsyncClient { if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; } else { - // send the incoming text without context back to the sender - Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + Self::handle_jsonrpc_response(t.as_bytes(), callback.clone()).await; + //close the newly created websocket here. + let _ = new_wtx.close().await; } } }, @@ -319,14 +320,19 @@ impl ThunderAsyncClient { Ok(updated_request) => { debug!("Sending request to thunder {:?}", updated_request); for r in updated_request { - let url_clone = url.to_string(); - let callback_clone = callback.clone(); - let self_clone = self.clone(); - tokio::spawn({ - async move { - Self::process_new_req(&self_clone, r, url_clone, callback_clone.clone()).await; - } - }); + //check if it's subscription call use the already existing websocket for sending + if r.contains(".register") { + let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + let _flush = ws_tx.flush().await; + } else { + let url_clone = url.to_string(); + let callback_clone = callback.clone(); + let self_clone = self.clone(); + tokio::spawn(async move { + self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; + } + ); + } } } Err(e) => { From a559862460b7c917728c24e48d93e048cbdcb592 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 24 Jan 2025 16:05:28 +0530 Subject: [PATCH 41/51] fix: review comment fixed related to websocket routing based on request type --- .../src/client/thunder_async_client.rs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 1b8f79238..1a746c8c0 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -320,18 +320,25 @@ impl ThunderAsyncClient { Ok(updated_request) => { debug!("Sending request to thunder {:?}", updated_request); for r in updated_request { - //check if it's subscription call use the already existing websocket for sending - if r.contains(".register") { - let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - let _flush = ws_tx.flush().await; - } else { - let url_clone = url.to_string(); - let callback_clone = callback.clone(); - let self_clone = self.clone(); - tokio::spawn(async move { - self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; - } - ); + match request.request { + DeviceChannelRequest::Subscribe(_) => { + let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + let _flush = ws_tx.flush().await; + }, + DeviceChannelRequest::Unsubscribe(_) => { + let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + let _flush = ws_tx.flush().await; + }, + DeviceChannelRequest::Call(_) =>{ + let url_clone = url.to_string(); + let callback_clone = callback.clone(); + let self_clone = self.clone(); + tokio::spawn(async move { + self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; + } + ); + } + } } } From 707c7558bc1b4f79313e1afaa86ef8647a9143e9 Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Fri, 24 Jan 2025 09:42:26 -0500 Subject: [PATCH 42/51] PCA: Changes to reduce boilerplate --- .../src/client/thunder_async_client.rs | 160 +++++++++++++----- 1 file changed, 118 insertions(+), 42 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 1a746c8c0..6d78c32e5 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -235,38 +235,93 @@ impl ThunderAsyncClient { } } - pub async fn process_new_req(&self, request: String, url: String, callback: AsyncCallback) { - let (mut new_wtx, mut new_wrx) = Self::create_ws(&url).await; - let _feed = new_wtx + // + // pub async fn process_new_req(&self, request: String, url: String, callback: AsyncCallback) { + // let (mut new_wtx, mut new_wrx) = Self::create_ws(&url).await; + // let _feed = new_wtx + // .feed(tokio_tungstenite::tungstenite::Message::Text(request)) + // .await; + // let _flush = new_wtx.flush().await; + + // tokio::pin! { + // let read = new_wrx.next(); + // } + + // tokio::select! { + // Some(value) = &mut read => { + // match value { + // Ok(v) => { + // if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + // if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { + // self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; + // } else { + // Self::handle_jsonrpc_response(t.as_bytes(), callback.clone()).await; + // //close the newly created websocket here. + // let _ = new_wtx.close().await; + // } + // } + // }, + // Err(e) => { + // error!("thunder_async_client Websocket error on read {:?}", e); + // } + // } + // } + // } + // } + pub async fn process_new_req(&self, request: String, url: String) { + let (mut ws_tx, mut ws_rx) = Self::create_ws(&url).await; + let _feed = ws_tx .feed(tokio_tungstenite::tungstenite::Message::Text(request)) .await; - let _flush = new_wtx.flush().await; + let _flush = ws_tx.flush().await; - tokio::pin! { - let read = new_wrx.next(); + // tokio::pin! { + // let read = new_wrx.next(); + // } + + // tokio::select! { + // Some(value) = &mut read => { + // match value { + // Ok(v) => { + // self.handle_response(v).await; + // }, + // Err(e) => { + // error!("thunder_async_client Websocket error on read {:?}", e); + // } + // } + // } + // } + if let Some(resp) = ws_rx.next().await { + match resp { + Ok(message) => { + self.handle_response(message).await; + } + Err(e) => { + error!("thunder_async_client Websocket error on read {:?}", e); + } + } } + } + // - tokio::select! { - Some(value) = &mut read => { - match value { - Ok(v) => { - if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { - self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; - } else { - Self::handle_jsonrpc_response(t.as_bytes(), callback.clone()).await; - //close the newly created websocket here. - let _ = new_wtx.close().await; - } - } - }, - Err(e) => { - error!("thunder_async_client Websocket error on read {:?}", e); - } - } + // + async fn handle_response(&self, message: Message) { + if let Message::Text(t) = message { + let request = t.as_bytes(); + if self + .status_manager + .is_controller_response(self.get_sender(), self.callback.clone(), request) + .await + { + self.status_manager + .handle_controller_response(self.get_sender(), self.callback.clone(), request) + .await; + } else { + Self::handle_jsonrpc_response(request, self.callback.clone()).await } } } + // pub async fn start( &self, @@ -296,16 +351,19 @@ impl ThunderAsyncClient { Some(value) = &mut read => { match value { Ok(v) => { - if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { - client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; - } - else { - //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose - // send the incoming text without context back to the sender - Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await - } - } + // + //if let tokio_tungstenite::tungstenite::Message::Text(t) = v { + // if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { + // client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; + // } + // else { + // //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose + // // send the incoming text without context back to the sender + // Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await + // } + //} + self.handle_response(v).await; + // }, Err(e) => { error!("Thunder_async_client Websocket error on read {:?}", e); @@ -320,26 +378,44 @@ impl ThunderAsyncClient { Ok(updated_request) => { debug!("Sending request to thunder {:?}", updated_request); for r in updated_request { + // + // match request.request { + // DeviceChannelRequest::Subscribe(_) => { + // let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + // let _flush = ws_tx.flush().await; + // }, + // DeviceChannelRequest::Unsubscribe(_) => { + // let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; + // let _flush = ws_tx.flush().await; + // }, + // DeviceChannelRequest::Call(_) =>{ + // let url_clone = url.to_string(); + // let callback_clone = callback.clone(); + // let self_clone = self.clone(); + // tokio::spawn(async move { + // self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; + // } + // ); + // } + + // } match request.request { DeviceChannelRequest::Subscribe(_) => { let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; let _flush = ws_tx.flush().await; + }, - DeviceChannelRequest::Unsubscribe(_) => { - let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - let _flush = ws_tx.flush().await; - }, - DeviceChannelRequest::Call(_) =>{ + _ => { + let thunder_async_client = self.clone(); let url_clone = url.to_string(); - let callback_clone = callback.clone(); - let self_clone = self.clone(); tokio::spawn(async move { - self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; + thunder_async_client.process_new_req(r, url_clone).await; } ); } } + // } } Err(e) => { From a02a97446a451a4ea0dc0bbc14fd688eab147030 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Fri, 24 Jan 2025 22:00:59 +0530 Subject: [PATCH 43/51] fix: added the websocket close call chore: cleanup the commented lines of code --- .../src/client/thunder_async_client.rs | 94 +------------------ 1 file changed, 5 insertions(+), 89 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 6d78c32e5..ea11a55be 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -235,39 +235,6 @@ impl ThunderAsyncClient { } } - // - // pub async fn process_new_req(&self, request: String, url: String, callback: AsyncCallback) { - // let (mut new_wtx, mut new_wrx) = Self::create_ws(&url).await; - // let _feed = new_wtx - // .feed(tokio_tungstenite::tungstenite::Message::Text(request)) - // .await; - // let _flush = new_wtx.flush().await; - - // tokio::pin! { - // let read = new_wrx.next(); - // } - - // tokio::select! { - // Some(value) = &mut read => { - // match value { - // Ok(v) => { - // if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - // if self.status_manager.is_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await { - // self.status_manager.handle_controller_response(self.get_sender(), callback.clone(), t.as_bytes()).await; - // } else { - // Self::handle_jsonrpc_response(t.as_bytes(), callback.clone()).await; - // //close the newly created websocket here. - // let _ = new_wtx.close().await; - // } - // } - // }, - // Err(e) => { - // error!("thunder_async_client Websocket error on read {:?}", e); - // } - // } - // } - // } - // } pub async fn process_new_req(&self, request: String, url: String) { let (mut ws_tx, mut ws_rx) = Self::create_ws(&url).await; let _feed = ws_tx @@ -275,26 +242,12 @@ impl ThunderAsyncClient { .await; let _flush = ws_tx.flush().await; - // tokio::pin! { - // let read = new_wrx.next(); - // } - - // tokio::select! { - // Some(value) = &mut read => { - // match value { - // Ok(v) => { - // self.handle_response(v).await; - // }, - // Err(e) => { - // error!("thunder_async_client Websocket error on read {:?}", e); - // } - // } - // } - // } if let Some(resp) = ws_rx.next().await { match resp { Ok(message) => { self.handle_response(message).await; + //close the newly created websocket + let _ = ws_tx.close().await; } Err(e) => { error!("thunder_async_client Websocket error on read {:?}", e); @@ -302,12 +255,11 @@ impl ThunderAsyncClient { } } } - // - // async fn handle_response(&self, message: Message) { if let Message::Text(t) = message { let request = t.as_bytes(); + //check controller response or not if self .status_manager .is_controller_response(self.get_sender(), self.callback.clone(), request) @@ -321,7 +273,6 @@ impl ThunderAsyncClient { } } } - // pub async fn start( &self, @@ -351,19 +302,7 @@ impl ThunderAsyncClient { Some(value) = &mut read => { match value { Ok(v) => { - // - //if let tokio_tungstenite::tungstenite::Message::Text(t) = v { - // if client_c.status_manager.is_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await { - // client_c.status_manager.handle_controller_response(client_c.get_sender(), callback.clone(), t.as_bytes()).await; - // } - // else { - // //let _id = Self::get_id_from_result(t.as_bytes()); for debug purpose - // // send the incoming text without context back to the sender - // Self::handle_jsonrpc_response(t.as_bytes(),callback.clone()).await - // } - //} - self.handle_response(v).await; - // + self.handle_response(v).await; }, Err(e) => { error!("Thunder_async_client Websocket error on read {:?}", e); @@ -378,32 +317,11 @@ impl ThunderAsyncClient { Ok(updated_request) => { debug!("Sending request to thunder {:?}", updated_request); for r in updated_request { - // - // match request.request { - // DeviceChannelRequest::Subscribe(_) => { - // let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - // let _flush = ws_tx.flush().await; - // }, - // DeviceChannelRequest::Unsubscribe(_) => { - // let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - // let _flush = ws_tx.flush().await; - // }, - // DeviceChannelRequest::Call(_) =>{ - // let url_clone = url.to_string(); - // let callback_clone = callback.clone(); - // let self_clone = self.clone(); - // tokio::spawn(async move { - // self_clone.process_new_req(r, url_clone, callback_clone.clone()).await; - // } - // ); - // } - - // } match request.request { + //if request type is subscription send the request through existing websocket DeviceChannelRequest::Subscribe(_) => { let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; let _flush = ws_tx.flush().await; - }, _ => { let thunder_async_client = self.clone(); @@ -413,9 +331,7 @@ impl ThunderAsyncClient { } ); } - } - // } } Err(e) => { From 943942441fe1c8a83045d36f1402a5da6b0747e1 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Mon, 27 Jan 2025 17:11:57 +0530 Subject: [PATCH 44/51] chore: cleanup of unused functions --- .../thunder_ripple_sdk/src/client/device_operator.rs | 12 ------------ .../thunder_ripple_sdk/src/client/thunder_client.rs | 1 - 2 files changed, 13 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/device_operator.rs b/device/thunder_ripple_sdk/src/client/device_operator.rs index 00475a652..21478267e 100644 --- a/device/thunder_ripple_sdk/src/client/device_operator.rs +++ b/device/thunder_ripple_sdk/src/client/device_operator.rs @@ -64,18 +64,6 @@ impl DeviceChannelRequest { DeviceChannelRequest::Unsubscribe(u) => (u.module.clone(), u.event_name.clone()), } } - - pub fn is_subscription(&self) -> bool { - !matches!(self, DeviceChannelRequest::Call(_)) - } - - pub fn is_unsubscribe(&self) -> Option { - if let DeviceChannelRequest::Unsubscribe(u) = self { - Some(u.clone()) - } else { - None - } - } } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 9ba77cd67..03c80c204 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -75,7 +75,6 @@ impl ThunderClientManager { .start(&thndr_endpoint_url, request_tr) .await; } - error!("Thunder disconnected so reconnecting"); }); /*thunder async response will get here */ tokio::spawn(async move { From b66b9a939572e72008407fbd67cff45716230f3e Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 29 Jan 2025 15:19:35 +0530 Subject: [PATCH 45/51] fix: try to add websocket disconnection handling changes --- .../src/client/thunder_async_client.rs | 41 +++++++++++++++++-- .../src/client/thunder_client.rs | 11 ++++- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index ea11a55be..37dd62546 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -19,6 +19,8 @@ use super::{ device_operator::{DeviceChannelRequest, DeviceResponseMessage}, thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender, StatusManager}, }; +use crate::client::thunder_client; +use crate::thunder_state::ThunderConnectionState; use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; @@ -29,7 +31,10 @@ use ripple_sdk::{ utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; use serde_json::json; -use std::time::Duration; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::time::{sleep, Duration}; +//use std::time::Duration; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; #[derive(Clone, Debug)] @@ -37,6 +42,7 @@ pub struct ThunderAsyncClient { status_manager: StatusManager, sender: AsyncSender, callback: AsyncCallback, + sub_map: HashMap, } #[derive(Clone, Debug)] @@ -60,8 +66,6 @@ pub struct ThunderAsyncResponse { pub result: Result, } -impl ThunderAsyncClient {} - impl ThunderAsyncResponse { fn new_response(response: JsonRpcApiResponse) -> Self { Self { @@ -232,6 +236,7 @@ impl ThunderAsyncClient { status_manager: StatusManager::new(), sender, callback, + sub_map: HashMap::new(), } } @@ -276,6 +281,8 @@ impl ThunderAsyncClient { pub async fn start( &self, + thunder_connectionstate: Option>, + thunder_client: &thunder_client::ThunderClient, url: &str, mut tr: Receiver, ) -> Receiver { @@ -294,6 +301,7 @@ impl ThunderAsyncClient { let _flush = ws_tx.flush().await; let client_c = self.clone(); let callback_for_sender = callback.clone(); + tokio::pin! { let read = ws_rx.next(); } @@ -350,7 +358,26 @@ impl ThunderAsyncClient { } } } - // when WS is disconnected return the tr back to caller helps restabilish connection + + // { + // let thunder_connectionstate = thunder_connectionstate.clone().unwrap(); + // let mut is_connecting = thunder_connectionstate.conn_status_mutex.lock().await; + // // check if we are already reconnecting + // if *is_connecting { + // drop(is_connecting); + // // wait for the connection to be ready + // thunder_connectionstate.conn_status_notify.notified().await; + // } else { + // //Mark the connection as reconnecting + // *is_connecting = true; + // } + // } // Lock is released here + + let url_clone = url.to_string(); + let delay: Duration = tokio::time::Duration::from_millis(50); + sleep(delay).await; + let (mut ws_tx, mut ws_rx) = Self::create_ws(&url_clone).await; + tr } @@ -371,6 +398,12 @@ impl ThunderAsyncClient { error!("Failed to send thunder Async Request: {:?}", e); } } + + pub async fn add_sub_req_list(&mut self, request: ThunderAsyncRequest) { + let mut sub_map = self.sub_map.clone(); + sub_map.insert(request.id, request); + self.sub_map = sub_map; + } } #[cfg(test)] diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 03c80c204..f22c1cd79 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -66,13 +66,19 @@ impl ThunderClientManager { request_tr: Receiver, mut response_tr: Receiver, thndr_endpoint_url: String, + thunder_connection_state: Option>, ) { let client_c = client.clone(); tokio::spawn(async move { if let Some(thndr_asynclient) = &client_c.thunder_async_client { thndr_asynclient - .start(&thndr_endpoint_url, request_tr) + .start( + thunder_connection_state, + &client_c, + &thndr_endpoint_url, + request_tr, + ) .await; } }); @@ -286,8 +292,10 @@ impl DeviceOperator for ThunderClient { } else if let Some(subscribe_request) = self.add_subscription_handler(&request, handler.clone()) { + let (tx, rx) = oneshot::channel::(); self.add_callback(&subscribe_request, tx); + if let Some(async_client) = &self.thunder_async_client { async_client.send(subscribe_request).await; } @@ -835,6 +843,7 @@ impl ThunderClientBuilder { broker_rx, resp_rx, url.to_string(), + thunder_connection_state, ); Ok(thunder_client) } From 161724640599335f9309ff7384437d819527ec3d Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Thu, 30 Jan 2025 09:01:21 -0500 Subject: [PATCH 46/51] Revert "fix: try to add websocket disconnection handling changes" This reverts commit b66b9a939572e72008407fbd67cff45716230f3e. --- .../src/client/thunder_async_client.rs | 41 ++----------------- .../src/client/thunder_client.rs | 11 +---- 2 files changed, 5 insertions(+), 47 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 37dd62546..ea11a55be 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -19,8 +19,6 @@ use super::{ device_operator::{DeviceChannelRequest, DeviceResponseMessage}, thunder_async_client_plugins_status_mgr::{AsyncCallback, AsyncSender, StatusManager}, }; -use crate::client::thunder_client; -use crate::thunder_state::ThunderConnectionState; use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; @@ -31,10 +29,7 @@ use ripple_sdk::{ utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; use serde_json::json; -use std::collections::HashMap; -use std::sync::Arc; -use tokio::time::{sleep, Duration}; -//use std::time::Duration; +use std::time::Duration; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; #[derive(Clone, Debug)] @@ -42,7 +37,6 @@ pub struct ThunderAsyncClient { status_manager: StatusManager, sender: AsyncSender, callback: AsyncCallback, - sub_map: HashMap, } #[derive(Clone, Debug)] @@ -66,6 +60,8 @@ pub struct ThunderAsyncResponse { pub result: Result, } +impl ThunderAsyncClient {} + impl ThunderAsyncResponse { fn new_response(response: JsonRpcApiResponse) -> Self { Self { @@ -236,7 +232,6 @@ impl ThunderAsyncClient { status_manager: StatusManager::new(), sender, callback, - sub_map: HashMap::new(), } } @@ -281,8 +276,6 @@ impl ThunderAsyncClient { pub async fn start( &self, - thunder_connectionstate: Option>, - thunder_client: &thunder_client::ThunderClient, url: &str, mut tr: Receiver, ) -> Receiver { @@ -301,7 +294,6 @@ impl ThunderAsyncClient { let _flush = ws_tx.flush().await; let client_c = self.clone(); let callback_for_sender = callback.clone(); - tokio::pin! { let read = ws_rx.next(); } @@ -358,26 +350,7 @@ impl ThunderAsyncClient { } } } - - // { - // let thunder_connectionstate = thunder_connectionstate.clone().unwrap(); - // let mut is_connecting = thunder_connectionstate.conn_status_mutex.lock().await; - // // check if we are already reconnecting - // if *is_connecting { - // drop(is_connecting); - // // wait for the connection to be ready - // thunder_connectionstate.conn_status_notify.notified().await; - // } else { - // //Mark the connection as reconnecting - // *is_connecting = true; - // } - // } // Lock is released here - - let url_clone = url.to_string(); - let delay: Duration = tokio::time::Duration::from_millis(50); - sleep(delay).await; - let (mut ws_tx, mut ws_rx) = Self::create_ws(&url_clone).await; - + // when WS is disconnected return the tr back to caller helps restabilish connection tr } @@ -398,12 +371,6 @@ impl ThunderAsyncClient { error!("Failed to send thunder Async Request: {:?}", e); } } - - pub async fn add_sub_req_list(&mut self, request: ThunderAsyncRequest) { - let mut sub_map = self.sub_map.clone(); - sub_map.insert(request.id, request); - self.sub_map = sub_map; - } } #[cfg(test)] diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index f22c1cd79..03c80c204 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -66,19 +66,13 @@ impl ThunderClientManager { request_tr: Receiver, mut response_tr: Receiver, thndr_endpoint_url: String, - thunder_connection_state: Option>, ) { let client_c = client.clone(); tokio::spawn(async move { if let Some(thndr_asynclient) = &client_c.thunder_async_client { thndr_asynclient - .start( - thunder_connection_state, - &client_c, - &thndr_endpoint_url, - request_tr, - ) + .start(&thndr_endpoint_url, request_tr) .await; } }); @@ -292,10 +286,8 @@ impl DeviceOperator for ThunderClient { } else if let Some(subscribe_request) = self.add_subscription_handler(&request, handler.clone()) { - let (tx, rx) = oneshot::channel::(); self.add_callback(&subscribe_request, tx); - if let Some(async_client) = &self.thunder_async_client { async_client.send(subscribe_request).await; } @@ -843,7 +835,6 @@ impl ThunderClientBuilder { broker_rx, resp_rx, url.to_string(), - thunder_connection_state, ); Ok(thunder_client) } From 3599e4034ee3c92d9aaa5f5b3282ee46eda45e96 Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Fri, 31 Jan 2025 16:35:45 -0500 Subject: [PATCH 47/51] ThunderAsyncClient: Added reconnect/resubscribe logic. --- .gitignore | 2 + core/sdk/src/api/gateway/rpc_gateway_api.rs | 2 +- .../src/client/thunder_async_client.rs | 296 ++++++++++-------- .../src/client/thunder_client.rs | 14 +- 4 files changed, 169 insertions(+), 145 deletions(-) diff --git a/.gitignore b/.gitignore index 248f2ad0c..983e88fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ Cargo.lock /device/thunder_ripple_sdk/target/ .DS_Store + +/device/mock_device/stats.json diff --git a/core/sdk/src/api/gateway/rpc_gateway_api.rs b/core/sdk/src/api/gateway/rpc_gateway_api.rs index 88a9f1282..2da86c63d 100644 --- a/core/sdk/src/api/gateway/rpc_gateway_api.rs +++ b/core/sdk/src/api/gateway/rpc_gateway_api.rs @@ -224,7 +224,7 @@ impl ApiBaseRequest { } } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct JsonRpcApiRequest { pub jsonrpc: String, pub id: Option, diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index ea11a55be..c12bb9f00 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -23,13 +23,13 @@ use crate::utils::get_next_id; use futures::stream::{SplitSink, SplitStream}; use futures_util::{SinkExt, StreamExt}; use ripple_sdk::{ - api::gateway::rpc_gateway_api::JsonRpcApiResponse, + api::gateway::rpc_gateway_api::{JsonRpcApiRequest, JsonRpcApiResponse}, log::{debug, error, info}, tokio::{self, net::TcpStream, sync::mpsc::Receiver}, utils::{error::RippleError, rpc_utils::extract_tcp_port}, }; -use serde_json::json; -use std::time::Duration; +use serde_json::{json, Value}; +use std::{collections::HashMap, time::Duration}; use tokio_tungstenite::{client_async, tungstenite::Message, WebSocketStream}; #[derive(Clone, Debug)] @@ -37,6 +37,7 @@ pub struct ThunderAsyncClient { status_manager: StatusManager, sender: AsyncSender, callback: AsyncCallback, + subscriptions: HashMap, } #[derive(Clone, Debug)] @@ -114,7 +115,7 @@ impl ThunderAsyncClient { SplitSink, Message>, SplitStream>, ) { - info!("Thunder_async_client Endpoint url {}", endpoint); + debug!("create_ws: {}", endpoint); let port = extract_tcp_port(endpoint); let tcp_port = port.unwrap(); let mut index = 0; @@ -122,6 +123,7 @@ impl ThunderAsyncClient { loop { // Try connecting to the tcp port first if let Ok(v) = TcpStream::connect(&tcp_port).await { + debug!("create_ws: Connected"); // Setup handshake for websocket with the tcp port // Some WS servers lock on to the Port but not setup handshake till they are fully setup if let Ok((stream, _)) = client_async(endpoint, v).await { @@ -130,7 +132,7 @@ impl ThunderAsyncClient { } if (index % 10).eq(&0) { error!( - "Thunder_async_client with {} failed with retry for last {} secs in {}", + "create_ws: endpoint {} failed with retry for last {} secs in {}", endpoint, index, tcp_port ); } @@ -139,8 +141,7 @@ impl ThunderAsyncClient { } } - fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result, RippleError> { - let mut requests = Vec::new(); + fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result { let id: u64 = request.id; let (callsign, method) = request.request.get_callsign_method(); @@ -160,8 +161,7 @@ impl ThunderAsyncClient { let request = self .status_manager .generate_plugin_status_request(callsign.clone()); - requests.push(request.to_string()); - return Ok(requests); + return Ok(request.to_string()); } }; @@ -184,47 +184,41 @@ impl ThunderAsyncClient { let request = self .status_manager .generate_plugin_activation_request(callsign.clone()); - requests.push(request.to_string()); - return Ok(requests); + return Ok(request.to_string()); } // Generate the appropriate JSON-RPC request based on the type of DeviceChannelRequest - match &request.request { - DeviceChannelRequest::Call(c) => requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": c.method, - "params": c.params - }) - .to_string(), - ), - DeviceChannelRequest::Unsubscribe(_) => requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.unregister", callsign), - "params": { - "event": method, - "id": "client.events" - } - }) - .to_string(), - ), - DeviceChannelRequest::Subscribe(_) => requests.push( - json!({ - "jsonrpc": "2.0", - "id": id, - "method": format!("{}.register", callsign), - "params": json!({ - "event": method, - "id": "client.events" - }) + let r = match &request.request { + DeviceChannelRequest::Call(c) => json!({ + "jsonrpc": "2.0", + "id": id, + "method": c.method, + "params": c.params + }) + .to_string(), + DeviceChannelRequest::Unsubscribe(_) => json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.unregister", callsign), + "params": { + "event": method, + "id": "client.events" + } + }) + .to_string(), + DeviceChannelRequest::Subscribe(_) => json!({ + "jsonrpc": "2.0", + "id": id, + "method": format!("{}.register", callsign), + "params": json!({ + "event": method, + "id": "client.events" }) - .to_string(), - ), - } - Ok(requests) + }) + .to_string(), + }; + + Ok(r) } pub fn new(callback: AsyncCallback, sender: AsyncSender) -> Self { @@ -232,10 +226,11 @@ impl ThunderAsyncClient { status_manager: StatusManager::new(), sender, callback, + subscriptions: HashMap::new(), } } - pub async fn process_new_req(&self, request: String, url: String) { + pub async fn process_new_req(&mut self, request: String, url: String) { let (mut ws_tx, mut ws_rx) = Self::create_ws(&url).await; let _feed = ws_tx .feed(tokio_tungstenite::tungstenite::Message::Text(request)) @@ -256,7 +251,7 @@ impl ThunderAsyncClient { } } - async fn handle_response(&self, message: Message) { + async fn handle_response(&mut self, message: Message) { if let Message::Text(t) = message { let request = t.as_bytes(); //check controller response or not @@ -269,100 +264,139 @@ impl ThunderAsyncClient { .handle_controller_response(self.get_sender(), self.callback.clone(), request) .await; } else { - Self::handle_jsonrpc_response(request, self.callback.clone()).await + self.handle_jsonrpc_response(request).await } } } + async fn process_subscribe_requests( + &mut self, + ws_tx: &mut SplitSink, Message>, + ) { + for (_, subscription_request) in self.subscriptions.iter_mut() { + let new_id = get_next_id(); + + debug!( + "process_subscribe_requests: method={}, params={:?}, old_id={:?}, new_id={}", + subscription_request.method, + subscription_request.params, + subscription_request.id, + new_id + ); + + subscription_request.id = Some(new_id); + + let request_json = serde_json::to_string(&subscription_request).unwrap(); + let _feed = ws_tx + .feed(tokio_tungstenite::tungstenite::Message::Text(request_json)) + .await; + } + } + pub async fn start( - &self, + &mut self, url: &str, - mut tr: Receiver, - ) -> Receiver { - let callback = self.callback.clone(); - let (mut ws_tx, mut ws_rx) = Self::create_ws(url).await; - // send the controller statechange subscription request - let status_request = self - .status_manager - .generate_state_change_subscribe_request(); - - let _feed = ws_tx - .feed(tokio_tungstenite::tungstenite::Message::Text( - status_request.to_string(), - )) - .await; - let _flush = ws_tx.flush().await; - let client_c = self.clone(); - let callback_for_sender = callback.clone(); - tokio::pin! { - let read = ws_rx.next(); - } + mut thunder_async_request_rx: Receiver, + ) { loop { - tokio::select! { - Some(value) = &mut read => { - match value { - Ok(v) => { - self.handle_response(v).await; - }, - Err(e) => { - error!("Thunder_async_client Websocket error on read {:?}", e); - break; + info!("start: (re)establishing websocket connection: url={}", url); + + let (mut subscriptions_tx, mut subscriptions_rx) = Self::create_ws(url).await; + + // send the controller statechange subscription request + let status_request = self + .status_manager + .generate_state_change_subscribe_request(); + + let _feed = subscriptions_tx + .feed(tokio_tungstenite::tungstenite::Message::Text( + status_request.to_string(), + )) + .await; + + self.process_subscribe_requests(&mut subscriptions_tx).await; + + let _flush = subscriptions_tx.flush().await; + + tokio::pin! { + let subscriptions_socket = subscriptions_rx.next(); + } + + loop { + tokio::select! { + Some(value) = &mut subscriptions_socket => { + match value { + Ok(message) => { + self.handle_response(message).await; + }, + Err(e) => { + error!("Thunder_async_client Websocket error on read {:?}", e); + break; + } } - } - }, - Some(request) = tr.recv() => { - debug!("Got request from receiver for thunder {:?}", request); - // here prepare_request will check the plugin status and add json rpc format - match client_c.prepare_request(&request) { - Ok(updated_request) => { - debug!("Sending request to thunder {:?}", updated_request); - for r in updated_request { - match request.request { - //if request type is subscription send the request through existing websocket - DeviceChannelRequest::Subscribe(_) => { - let _feed = ws_tx.feed(tokio_tungstenite::tungstenite::Message::Text(r)).await; - let _flush = ws_tx.flush().await; - }, - _ => { - let thunder_async_client = self.clone(); - let url_clone = url.to_string(); - tokio::spawn(async move { - thunder_async_client.process_new_req(r, url_clone).await; + }, + Some(request) = thunder_async_request_rx.recv() => { + debug!("thunder_async_request_rx: request={:?}", request); + // here prepare_request will check the plugin status and add json rpc format + match self.prepare_request(&request) { + Ok(updated_request) => { + if let Ok(jsonrpc_request) = serde_json::from_str::(&updated_request) { + if jsonrpc_request.method.ends_with(".register") { + if let Some(Value::Object(ref params)) = jsonrpc_request.params { + if let Some(Value::String(event)) = params.get("event") { + debug!("thunder_async_request_rx: Rerouting subscription request for {}", event); + + // Store the subscription request in the subscriptions list in case we need to + // resubscribe later due to a socket disconnect. + self.subscriptions.insert(event.to_string(), jsonrpc_request.clone()); + + // Reroute subsubscription requests through the persistent websocket so all notifications + // are sent to the same websocket connection. + let _feed = subscriptions_tx.feed(tokio_tungstenite::tungstenite::Message::Text(updated_request)).await; + let _flush = subscriptions_tx.flush().await; + } else { + error!("thunder_async_request_rx: Missing 'event' parameter"); } - ); + } else { + error!("thunder_async_request_rx: Missing 'params' object"); + } + } else { + // TODO: I don't like that we have to clone the client, we should refactor this. -pca + let mut thunder_async_client = self.clone(); + let url_clone = url.to_string(); + tokio::spawn(async move { + thunder_async_client.process_new_req(updated_request, url_clone).await; + } + ); } } } - } - Err(e) => { - let response = ThunderAsyncResponse::new_error(request.id,e.clone()); - match e { - RippleError::ServiceNotReady => { - info!("Thunder Service not ready, request is now in pending list {:?}", request); - }, - _ => { - error!("error preparing request {:?}", e) + Err(e) => { + let response = ThunderAsyncResponse::new_error(request.id,e.clone()); + match e { + RippleError::ServiceNotReady => { + info!("Thunder Service not ready, request is now in pending list {:?}", request); + }, + _ => { + error!("error preparing request {:?}", e) + } } + self.callback.send(response).await; } - callback_for_sender.send(response).await; } } } } } - // when WS is disconnected return the tr back to caller helps restabilish connection - tr } - /// Default handler method for the thunder async client to remove the context and send it back to the - /// client for consumption - async fn handle_jsonrpc_response(result: &[u8], callback: AsyncCallback) { + async fn handle_jsonrpc_response(&mut self, result: &[u8]) { if let Ok(message) = serde_json::from_slice::(result) { - callback + self.callback .send(ThunderAsyncResponse::new_response(message)) .await } else { - error!("Invalid JSON RPC message sent by Thunder"); + error!("handle_jsonrpc_response: Invalid JSON RPC message sent by Thunder"); } } @@ -376,12 +410,9 @@ impl ThunderAsyncClient { #[cfg(test)] mod tests { use super::*; - use crate::client::{device_operator::DeviceCallRequest, thunder_client::ThunderClient}; + use crate::client::device_operator::DeviceCallRequest; use ripple_sdk::api::gateway::rpc_gateway_api::JsonRpcApiResponse; use ripple_sdk::utils::error::RippleError; - use ripple_sdk::uuid::Uuid; - use std::collections::HashMap; - use std::sync::{Arc, RwLock}; use tokio::sync::mpsc; #[tokio::test] @@ -517,7 +548,11 @@ mod tests { params: None, }; let response_bytes = serde_json::to_vec(&response).unwrap(); - ThunderAsyncClient::handle_jsonrpc_response(&response_bytes, callback).await; + let (async_tx, _async_rx) = mpsc::channel(1); + let async_sender = AsyncSender { sender: async_tx }; + let mut client = ThunderAsyncClient::new(callback, async_sender); + client.handle_jsonrpc_response(&response_bytes).await; + let received = resp_rx.recv().await; assert_eq!( received.unwrap().result.unwrap().result, @@ -531,19 +566,7 @@ mod tests { let callback = AsyncCallback { sender: resp_tx }; let (async_tx, _async_rx) = mpsc::channel(10); let async_sender = AsyncSender { sender: async_tx }; - let client = ThunderAsyncClient::new(callback.clone(), async_sender); - - let _thunder_client = ThunderClient { - sender: None, - pooled_sender: None, - id: Uuid::new_v4(), - plugin_manager_tx: None, - subscriptions: None, - thunder_async_client: Some(client), - thunder_async_subscriptions: Some(Arc::new(RwLock::new(HashMap::new()))), - thunder_async_callbacks: Some(Arc::new(RwLock::new(HashMap::new()))), - use_thunder_async: true, - }; + let mut client = ThunderAsyncClient::new(callback.clone(), async_sender); let response = json!({ "jsonrpc": "2.0", @@ -552,7 +575,8 @@ mod tests { } }); - ThunderAsyncClient::handle_jsonrpc_response(response.to_string().as_bytes(), callback) + client + .handle_jsonrpc_response(response.to_string().as_bytes()) .await; let received = resp_rx.recv().await; assert!(received.is_some()); diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index 03c80c204..138e34fb9 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -67,15 +67,13 @@ impl ThunderClientManager { mut response_tr: Receiver, thndr_endpoint_url: String, ) { - let client_c = client.clone(); + if let Some(ref thunder_async_client) = client.thunder_async_client { + let mut tac = thunder_async_client.clone(); + tokio::spawn(async move { + tac.start(&thndr_endpoint_url, request_tr).await; + }); + } - tokio::spawn(async move { - if let Some(thndr_asynclient) = &client_c.thunder_async_client { - thndr_asynclient - .start(&thndr_endpoint_url, request_tr) - .await; - } - }); /*thunder async response will get here */ tokio::spawn(async move { while let Some(response) = response_tr.recv().await { From 0c53700474ed60f6a6398484e9c7c0eaf83bb9c6 Mon Sep 17 00:00:00 2001 From: pahearn73 Date: Fri, 31 Jan 2025 17:03:45 -0500 Subject: [PATCH 48/51] ThunderAsyncClient: Attempt to resolve blackduck failure. --- .../thunder_ripple_sdk/src/client/thunder_async_client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index c12bb9f00..55ee938cf 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -189,11 +189,11 @@ impl ThunderAsyncClient { // Generate the appropriate JSON-RPC request based on the type of DeviceChannelRequest let r = match &request.request { - DeviceChannelRequest::Call(c) => json!({ + DeviceChannelRequest::Call(device_call_request) => json!({ "jsonrpc": "2.0", "id": id, - "method": c.method, - "params": c.params + "method": device_call_request.method, + "params": device_call_request.params }) .to_string(), DeviceChannelRequest::Unsubscribe(_) => json!({ From d28ec4588d24e037f859e20911e81ee187572c9a Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 5 Feb 2025 00:02:21 +0530 Subject: [PATCH 49/51] fix: review comments of single web socket usage for thunderasyncclient --- .../src/bootstrap/boot_thunder.rs | 13 +- .../src/client/device_operator.rs | 5 +- .../src/client/thunder_async_client.rs | 112 ++++++++++-------- 3 files changed, 75 insertions(+), 55 deletions(-) diff --git a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs index c41cfe0e3..e6ad12f5d 100644 --- a/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs +++ b/device/thunder_ripple_sdk/src/bootstrap/boot_thunder.rs @@ -51,11 +51,20 @@ pub async fn boot_thunder( plugin_param: ThunderPluginBootParam, ) -> Option { info!("Booting thunder initiated"); - //by default enabling the thunderBroker let state = if ext_client.get_bool_config("use_with_thunder_async_client") { info!("Using thunder_async_clinet"); let mut extn_client = ext_client.clone(); - let mut gateway_url = url::Url::parse(GATEWAY_DEFAULT).unwrap(); + let mut gateway_url = match url::Url::parse(GATEWAY_DEFAULT) { + Ok(url) => url, + Err(e) => { + error!( + "Could not parse default gateway URL '{}': {}", + GATEWAY_DEFAULT, e + ); + return None; + } + }; + let extn_message_response: Result = extn_client.request(Config::PlatformParameters).await; diff --git a/device/thunder_ripple_sdk/src/client/device_operator.rs b/device/thunder_ripple_sdk/src/client/device_operator.rs index 21478267e..a5c627675 100644 --- a/device/thunder_ripple_sdk/src/client/device_operator.rs +++ b/device/thunder_ripple_sdk/src/client/device_operator.rs @@ -154,8 +154,9 @@ impl DeviceResponseMessage { device_response_msg = Some(DeviceResponseMessage::new(er.clone(), sub_id)); } else if json_resp.clone().method.is_some() { if let Some(params) = &json_resp.params { - let dev_resp = serde_json::to_value(params).unwrap(); - device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); + if let Ok(dev_resp) = serde_json::to_value(params) { + device_response_msg = Some(DeviceResponseMessage::new(dev_resp, sub_id)); + } } } else { error!("deviceresponse msg extraction failed."); diff --git a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs index 55ee938cf..0c60ffbea 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_async_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_async_client.rs @@ -46,6 +46,16 @@ pub struct ThunderAsyncRequest { request: DeviceChannelRequest, } +impl std::fmt::Display for ThunderAsyncRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "ThunderAsyncRequest {{ id: {}, request: {:?} }}", + self.id, self.request + ) + } +} + impl ThunderAsyncRequest { pub fn new(request: DeviceChannelRequest) -> Self { Self { @@ -141,8 +151,10 @@ impl ThunderAsyncClient { } } - fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result { - let id: u64 = request.id; + fn check_and_generate_plugin_activation_request( + &self, + request: &ThunderAsyncRequest, + ) -> Result { let (callsign, method) = request.request.get_callsign_method(); // Check if the method is empty and return an error if it is @@ -186,9 +198,19 @@ impl ThunderAsyncClient { .generate_plugin_activation_request(callsign.clone()); return Ok(request.to_string()); } + Ok(request.to_string()) + } + + fn prepare_request(&self, request: &ThunderAsyncRequest) -> Result { + let id: u64 = request.id; + let (callsign, method) = request.request.get_callsign_method(); + // Check if the method is empty and return an error if it is + if method.is_empty() { + return Err(RippleError::InvalidInput); + } // Generate the appropriate JSON-RPC request based on the type of DeviceChannelRequest - let r = match &request.request { + let r: String = match &request.request { DeviceChannelRequest::Call(device_call_request) => json!({ "jsonrpc": "2.0", "id": id, @@ -230,27 +252,6 @@ impl ThunderAsyncClient { } } - pub async fn process_new_req(&mut self, request: String, url: String) { - let (mut ws_tx, mut ws_rx) = Self::create_ws(&url).await; - let _feed = ws_tx - .feed(tokio_tungstenite::tungstenite::Message::Text(request)) - .await; - let _flush = ws_tx.flush().await; - - if let Some(resp) = ws_rx.next().await { - match resp { - Ok(message) => { - self.handle_response(message).await; - //close the newly created websocket - let _ = ws_tx.close().await; - } - Err(e) => { - error!("thunder_async_client Websocket error on read {:?}", e); - } - } - } - } - async fn handle_response(&mut self, message: Message) { if let Message::Text(t) = message { let request = t.as_bytes(); @@ -337,38 +338,47 @@ impl ThunderAsyncClient { }, Some(request) = thunder_async_request_rx.recv() => { debug!("thunder_async_request_rx: request={:?}", request); - // here prepare_request will check the plugin status and add json rpc format - match self.prepare_request(&request) { - Ok(updated_request) => { - if let Ok(jsonrpc_request) = serde_json::from_str::(&updated_request) { - if jsonrpc_request.method.ends_with(".register") { - if let Some(Value::Object(ref params)) = jsonrpc_request.params { - if let Some(Value::String(event)) = params.get("event") { - debug!("thunder_async_request_rx: Rerouting subscription request for {}", event); - - // Store the subscription request in the subscriptions list in case we need to - // resubscribe later due to a socket disconnect. - self.subscriptions.insert(event.to_string(), jsonrpc_request.clone()); - - // Reroute subsubscription requests through the persistent websocket so all notifications - // are sent to the same websocket connection. - let _feed = subscriptions_tx.feed(tokio_tungstenite::tungstenite::Message::Text(updated_request)).await; - let _flush = subscriptions_tx.flush().await; + + match self.check_and_generate_plugin_activation_request(&request){ + Ok(_updated_request) => match self.prepare_request(&request){ + Ok(rpc_req) => { + if let Ok(jsonrpc_request) = serde_json::from_str::(&rpc_req) { + if jsonrpc_request.method.ends_with(".register") { + if let Some(Value::Object(ref params)) = jsonrpc_request.params { + if let Some(Value::String(event)) = params.get("event") { + debug!("thunder_async_request_rx: Rerouting subscription request for {}", event); + + // Store the subscription request in the subscriptions list in case we need to + // resubscribe later due to a socket disconnect. + self.subscriptions.insert(event.to_string(), jsonrpc_request.clone()); + + // Reroute subsubscription requests through the persistent websocket so all notifications + // are sent to the same websocket connection. + let _feed = subscriptions_tx.feed(tokio_tungstenite::tungstenite::Message::Text(rpc_req)).await; + let _flush = subscriptions_tx.flush().await; + } else { + error!("thunder_async_request_rx: Missing 'event' parameter"); + } } else { - error!("thunder_async_request_rx: Missing 'event' parameter"); + error!("thunder_async_request_rx: Missing 'params' object"); } } else { - error!("thunder_async_request_rx: Missing 'params' object"); + let _feed = subscriptions_tx.feed(tokio_tungstenite::tungstenite::Message::Text(rpc_req)).await; + let _flush = subscriptions_tx.flush().await; + } + } + } + Err(e) => { + let response = ThunderAsyncResponse::new_error(request.id,e.clone()); + match e { + RippleError::ServiceNotReady => { + info!("prepare request failed for request {:?}", request); + }, + _ => { + error!("error preparing request {:?}", e) } - } else { - // TODO: I don't like that we have to clone the client, we should refactor this. -pca - let mut thunder_async_client = self.clone(); - let url_clone = url.to_string(); - tokio::spawn(async move { - thunder_async_client.process_new_req(updated_request, url_clone).await; - } - ); } + self.callback.send(response).await; } } Err(e) => { From ca9a7fa08099c8f75e6362709d4b6288354c25bf Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 5 Feb 2025 14:18:49 +0530 Subject: [PATCH 50/51] fix: format check failure fix --- device/thunder_ripple_sdk/src/client/device_operator.rs | 6 ++++-- device/thunder_ripple_sdk/src/client/thunder_client.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/device/thunder_ripple_sdk/src/client/device_operator.rs b/device/thunder_ripple_sdk/src/client/device_operator.rs index 951e2fe95..9b42dbe60 100644 --- a/device/thunder_ripple_sdk/src/client/device_operator.rs +++ b/device/thunder_ripple_sdk/src/client/device_operator.rs @@ -15,8 +15,10 @@ // SPDX-License-Identifier: Apache-2.0 // use ripple_sdk::{ - api::gateway::rpc_gateway_api::JsonRpcApiResponse, async_trait::async_trait, log::error, - tokio::sync::{mpsc,oneshot::error::RecvError}, + api::gateway::rpc_gateway_api::JsonRpcApiResponse, + async_trait::async_trait, + log::error, + tokio::sync::{mpsc, oneshot::error::RecvError}, }; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/device/thunder_ripple_sdk/src/client/thunder_client.rs b/device/thunder_ripple_sdk/src/client/thunder_client.rs index e6b3fedc8..269948579 100644 --- a/device/thunder_ripple_sdk/src/client/thunder_client.rs +++ b/device/thunder_ripple_sdk/src/client/thunder_client.rs @@ -40,7 +40,7 @@ use ripple_sdk::{ serde_json::{self, json, Value}, tokio, tokio::sync::mpsc::{self, Receiver, Sender as MpscSender}, - tokio::sync::oneshot::{self, Sender as OneShotSender, error::RecvError}, + tokio::sync::oneshot::{self, error::RecvError, Sender as OneShotSender}, tokio::{sync::Mutex, task::JoinHandle, time::sleep}, utils::channel_utils::{mpsc_send_and_log, oneshot_send_and_log}, utils::error::RippleError, From 614bd09aacbaeea0efaf25775af1b38d26004dd1 Mon Sep 17 00:00:00 2001 From: nnaveen979 Date: Wed, 5 Feb 2025 15:18:36 +0530 Subject: [PATCH 51/51] fix: avoid unnecessary unwrap() --- core/sdk/src/utils/rpc_utils.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/sdk/src/utils/rpc_utils.rs b/core/sdk/src/utils/rpc_utils.rs index 712945926..79ad8c6ec 100644 --- a/core/sdk/src/utils/rpc_utils.rs +++ b/core/sdk/src/utils/rpc_utils.rs @@ -25,7 +25,11 @@ pub fn extract_tcp_port(url: &str) -> Result { let url_split: Vec<&str> = url.split("://").collect(); if let Some(domain) = url_split.get(1) { let domain_split: Vec<&str> = domain.split('/').collect(); - Ok(domain_split.first().unwrap().to_string()) + if let Some(first_part) = domain_split.first() { + Ok(first_part.to_string()) + } else { + Err(Error::Custom("Invalid domain format".to_string())) + } } else { Err(Error::Custom("Invalid URL format".to_string())) }