diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 0258c30a..6e88f4ea 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -84,7 +84,7 @@ async fn register_invehicle_digital_twin_service_with_chariott( Ok(()) } -/// Builds the enabled modules for the grpc server and starts the server. +/// Builds the enabled modules for the app server and starts the app server. /// /// # Arguments /// * `addr` - The address the server will be hosted on. @@ -98,7 +98,7 @@ async fn register_invehicle_digital_twin_service_with_chariott( /// 5. Call and return from the block `.add_module()` on the server with the updated middleware and /// module. #[allow(unused_assignments, unused_mut)] // Necessary when no extra modules are built. -async fn build_server_and_serve( +async fn build_app_server_and_serve( addr: SocketAddr, base_service: S, ) -> Result<(), Box> @@ -113,7 +113,7 @@ where let mut server: GrpcServer = GrpcServer::new(addr); #[cfg(feature = "managed_subscribe")] - // Adds the Managed Subscribe module to the service. + // Adds the Managed Subscribe module to the app server. let mut server = { // Initialize the Managed Subscribe module, which implements GrpcModule. let managed_subscribe_module = ManagedSubscribeModule::new().await.map_err(|error| { @@ -121,7 +121,7 @@ where error })?; - // Create interceptor layer to be added to the server. + // Create interceptor layer to be added to the app. let managed_subscribe_layer = GrpcInterceptorLayer::new(Box::new(managed_subscribe_module.create_interceptor())); @@ -136,7 +136,7 @@ where }; #[cfg(feature = "digital_twin_graph")] - // Adds the Digital Twin Graph module to the service. + // Adds the Digital Twin Graph module to the app server. let mut server = { // Initialize the Digital Twin Graph module, which implements GrpcModule. let digital_twin_graph_module = DigitalTwinGraphModule::new().await.map_err(|error| { @@ -151,7 +151,7 @@ where }; #[cfg(feature = "digital_twin_registry")] - // Adds the Digital Twin Registry module to the service. + // Adds the Digital Twin Registry module to the app server. let mut server = { // Initialize the Digital Twin Registry module, which implements GrpcModule. let digital_twin_registry_module = @@ -166,10 +166,10 @@ where server.add_module(server.middleware.clone(), Box::new(digital_twin_registry_module)) }; - // Construct the server. + // Construct the app server. let builder = server.construct_server().add_service(base_service); - // Start the server. + // Start the app server. builder.serve(addr).await.map_err(|error| error.into()) } @@ -243,8 +243,8 @@ async fn main() -> Result<(), Box> { let base_service = InvehicleDigitalTwinServer::new(invehicle_digital_twin_impl); - // Build and start the grpc server. - build_server_and_serve(addr, base_service).await?; + // Build and start the app server. + build_app_server_and_serve(addr, base_service).await?; debug!("The Digital Twin Service has completed."); diff --git a/core/module/digital_twin_graph/Cargo.toml b/core/module/digital_twin_graph/Cargo.toml index efa00c52..9991eca8 100644 --- a/core/module/digital_twin_graph/Cargo.toml +++ b/core/module/digital_twin_graph/Cargo.toml @@ -16,6 +16,7 @@ serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true , features = ["full"] } +tokio-retry = { workspace = true } tonic = { workspace = true } tower = { workspace = true } yaml-rust = { workspace = true } diff --git a/core/module/digital_twin_graph/src/digital_twin_graph_config.rs b/core/module/digital_twin_graph/src/digital_twin_graph_config.rs new file mode 100644 index 00000000..6abc51b6 --- /dev/null +++ b/core/module/digital_twin_graph/src/digital_twin_graph_config.rs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +use common::utils; +use serde_derive::Deserialize; + +const DEFAULT_CONFIG_FILENAME: &str = "digital_twin_graph_settings"; + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub base_authority: String, +} + +/// Load the settings. +pub fn load_settings() -> Settings { + utils::load_settings(DEFAULT_CONFIG_FILENAME).unwrap() +} + +/// Load the settings. +pub fn load_settings_with_config_filename(config_filename: &str) -> Settings { + utils::load_settings(config_filename).unwrap() +} diff --git a/core/module/digital_twin_graph/src/digital_twin_graph_impl.rs b/core/module/digital_twin_graph/src/digital_twin_graph_impl.rs index fbd23329..d15ffc6d 100644 --- a/core/module/digital_twin_graph/src/digital_twin_graph_impl.rs +++ b/core/module/digital_twin_graph/src/digital_twin_graph_impl.rs @@ -12,123 +12,147 @@ use core_protobuf_data_access::module::digital_twin_graph::v1::{ }; use core_protobuf_data_access::module::digital_twin_registry::v1::digital_twin_registry_client::DigitalTwinRegistryClient; use core_protobuf_data_access::module::digital_twin_registry::v1::{ - EndpointInfo, FindByInstanceIdRequest, FindByModelIdRequest, + EndpointInfo, FindByInstanceIdRequest, FindByInstanceIdResponse, FindByModelIdRequest, + FindByModelIdResponse, }; use log::{debug, info, warn}; use std::sync::Arc; use tokio::sync::broadcast; use tokio::time::{sleep, timeout, Duration}; +use tokio_retry::strategy::{jitter, ExponentialBackoff}; +use tokio_retry::Retry; use uuid::Uuid; use crate::{digital_twin_operation, digital_twin_protocol, TargetedPayload}; #[derive(Debug)] pub struct DigitalTwinGraphImpl { - invehicle_digital_twin_uri: String, + /// Digital Twin Registry URI. + digital_twin_registry_uri: String, + /// Respond URI. respond_uri: String, + /// The sender for the asynchronous channel for AnswerRequests. tx: Arc>, } impl DigitalTwinGraphImpl { + const BACKOFF_BASE_DURATION_IN_MILLIS: u64 = 100; + const MAX_RETRIES: usize = 100; + const TIMEOUT_PERIOD_IN_MILLIS: u64 = 5000; + /// Create a new instance of a DigitalTwinGraphImpl. /// /// # Arguments - /// * `invehicle_digital_twin_uri` - The uri for the invehicle digital twin service. + /// * `digital_twin_registry_uri` - The uri for the digital twin registry service. /// * `respond_uri` - The uri for the respond service. /// * `tx` - The sender for the asynchronous channel for AnswerRequest's. pub fn new( - invehicle_digital_twin_uri: &str, + digital_twin_registry_uri: &str, respond_uri: &str, tx: Arc>, ) -> DigitalTwinGraphImpl { DigitalTwinGraphImpl { - invehicle_digital_twin_uri: invehicle_digital_twin_uri.to_string(), + digital_twin_registry_uri: digital_twin_registry_uri.to_string(), respond_uri: respond_uri.to_string(), tx, } } -} -/// Is the provided subset a subset of the provided superset? -/// -/// # Arguments -/// * `subset` - The provided subset. -/// * `superset` - The provided superset. -fn is_subset(subset: &[String], superset: &[String]) -> bool { - subset.iter().all(|subset_member| { - superset.iter().any(|supserset_member| subset_member == supserset_member) - }) -} + /// Is the provided subset a subset of the provided superset? + /// + /// # Arguments + /// * `subset` - The provided subset. + /// * `superset` - The provided superset. + fn is_subset(subset: &[String], superset: &[String]) -> bool { + subset.iter().all(|subset_member| { + superset.iter().any(|supserset_member| subset_member == supserset_member) + }) + } -/// Use Ibeji to discover the endpoints for digital twin providers that satisfy the requirements. -/// -/// # Arguments -/// * `digitial_twin_registry_service_uri` - Digital Twin Registry Service URI. -/// * `model_id` - The matching model id. -/// * `protocol` - The required protocol. -/// * `operations` - The required operations. -pub async fn discover_digital_twin_providers_with_model_id( - digitial_twin_registry_service_uri: &str, - model_id: &str, - protocol: &str, - operations: &[String], -) -> Result, String> { - info!("Sending a find_by_model_id request for model id {model_id} to the Digital Twin Registry Service at {digitial_twin_registry_service_uri}"); - - let mut client = - DigitalTwinRegistryClient::connect(digitial_twin_registry_service_uri.to_string()) - .await - .map_err(|error| format!("{error}"))?; - let request = tonic::Request::new(FindByModelIdRequest { model_id: model_id.to_string() }); - let response = client.find_by_model_id(request).await.map_err(|error| error.to_string())?; - let response_inner = response.into_inner(); - debug!("Received the response for the find_by_model_id request"); - info!("response_payload: {:?}", response_inner.entity_access_info_list); - - Ok(response_inner - .entity_access_info_list - .iter() - .flat_map(|entity_access_info| entity_access_info.endpoint_info_list.clone()) - .filter(|endpoint_info| { - endpoint_info.protocol == protocol && is_subset(operations, &endpoint_info.operations) + /// Use the Digital Twin Registery service to discover the endpoints for digital twin providers that support the specified model id, protocol and operations. + /// Note: This operation will be retried when there is a failure. + /// + /// # Arguments + /// * `model_id` - The matching model id. + /// * `protocol` - The required protocol. + /// * `operations` - The required operations. + pub async fn discover_digital_twin_providers_with_model_id( + &self, + model_id: &str, + protocol: &str, + operations: &[String], + ) -> Result, String> { + let retry_strategy = ExponentialBackoff::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS) + .map(jitter) // add jitter to delays + .take(Self::MAX_RETRIES); + + let response: FindByModelIdResponse = Retry::spawn(retry_strategy.clone(), || async { + let mut client = + DigitalTwinRegistryClient::connect(self.digital_twin_registry_uri.to_string()) + .await + .map_err(|error| format!("{error}"))?; + + let request = + tonic::Request::new(FindByModelIdRequest { model_id: model_id.to_string() }); + + client.find_by_model_id(request).await.map_err(|error| error.to_string()) }) - .collect()) -} + .await? + .into_inner(); + + Ok(response + .entity_access_info_list + .iter() + .flat_map(|entity_access_info| entity_access_info.endpoint_info_list.clone()) + .filter(|endpoint_info| { + endpoint_info.protocol == protocol + && Self::is_subset(operations, &endpoint_info.operations) + }) + .collect()) + } -/// Use Ibeji to discover the endpoints for digital twin providers that satisfy the requirements. -/// -/// # Arguments -/// * `digitial_twin_registry_service_uri` - Digital Twin Registry Service URI. -/// * `instance_id` - The matching instance id. -/// * `protocol` - The required protocol. -/// * `operations` - The required operations. -pub async fn discover_digital_twin_providers_with_instance_id( - digitial_twin_registry_service_uri: &str, - instance_id: &str, - protocol: &str, - operations: &[String], -) -> Result, String> { - info!("Sending a find_by_instance_id request for instance id {instance_id} to the Digital Twin Registry Service at {digitial_twin_registry_service_uri}"); - - let mut client = - DigitalTwinRegistryClient::connect(digitial_twin_registry_service_uri.to_string()) - .await - .map_err(|error| format!("{error}"))?; - let request = - tonic::Request::new(FindByInstanceIdRequest { instance_id: instance_id.to_string() }); - let response = client.find_by_instance_id(request).await.map_err(|error| error.to_string())?; - let response_inner = response.into_inner(); - debug!("Received the response for the find_by_instance_id request"); - info!("response_payload: {:?}", response_inner.entity_access_info_list); - - Ok(response_inner - .entity_access_info_list - .iter() - .flat_map(|entity_access_info| entity_access_info.endpoint_info_list.clone()) - .filter(|endpoint_info| { - endpoint_info.protocol == protocol && is_subset(operations, &endpoint_info.operations) + /// Use the Digital Twin Registry service to discover the endpoints for digital twin providers that support the specified instance id, protocol and operations. + /// Note: This operation will be retried when there is a failure. + /// + /// # Arguments + /// * `instance_id` - The matching instance id. + /// * `protocol` - The required protocol. + /// * `operations` - The required operations. + pub async fn discover_digital_twin_providers_with_instance_id( + &self, + instance_id: &str, + protocol: &str, + operations: &[String], + ) -> Result, String> { + let retry_strategy = ExponentialBackoff::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS) + .map(jitter) // add jitter to delays + .take(Self::MAX_RETRIES); + + let response: FindByInstanceIdResponse = Retry::spawn(retry_strategy.clone(), || async { + let mut client = + DigitalTwinRegistryClient::connect(self.digital_twin_registry_uri.to_string()) + .await + .map_err(|error| format!("{error}"))?; + + let request = tonic::Request::new(FindByInstanceIdRequest { + instance_id: instance_id.to_string(), + }); + + client.find_by_instance_id(request).await.map_err(|error| error.to_string()) }) - .collect()) + .await? + .into_inner(); + + Ok(response + .entity_access_info_list + .iter() + .flat_map(|entity_access_info| entity_access_info.endpoint_info_list.clone()) + .filter(|endpoint_info| { + endpoint_info.protocol == protocol + && Self::is_subset(operations, &endpoint_info.operations) + }) + .collect()) + } } #[tonic::async_trait] @@ -144,19 +168,17 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { let request_inner = request.into_inner(); let model_id = request_inner.model_id; - info!("Received a find request for model id {model_id}"); + debug!("Received a find request for model id {model_id}"); // Retrieve the provider details. - let provider_endpoint_info_list = discover_digital_twin_providers_with_model_id( - &self.invehicle_digital_twin_uri, - model_id.as_str(), - digital_twin_protocol::GRPC, - &[digital_twin_operation::GET.to_string()], - ) - .await - .map_err(tonic::Status::internal)?; - - info!(">> Found the provider endpoint info list: {provider_endpoint_info_list:?}"); + let provider_endpoint_info_list = self + .discover_digital_twin_providers_with_model_id( + model_id.as_str(), + digital_twin_protocol::GRPC, + &[digital_twin_operation::GET.to_string()], + ) + .await + .map_err(tonic::Status::internal)?; let mut values = vec![]; @@ -196,15 +218,14 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { // Send the ask. let response = client.ask(request).await; if let Err(status) = response { - warn!("Unable to call ask, due to {status:?}\nWe will skip this one.."); + warn!("Unable to call ask, due to {status:?}\nWe will skip this one."); continue; } // Wait for the answer request. let mut answer_request: AnswerRequest = Default::default(); let mut attempts_after_failure = 0; - const MAX_ATTEMPTS_AFTER_FAILURE: u8 = 10; - while attempts_after_failure < MAX_ATTEMPTS_AFTER_FAILURE { + while attempts_after_failure < Self::MAX_RETRIES { match timeout(Duration::from_secs(5), rx.recv()).await { Ok(Ok(request)) => { if ask_id == request.ask_id { @@ -220,20 +241,20 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { } Ok(Err(error_message)) => { warn!("Failed to receive the answer request. The error message is '{}'. We will retry in a moment.", error_message); - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS)).await; attempts_after_failure += 1; continue; } Err(error_message) => { warn!("Failed to receive the answer request. The error message is '{}'. We will retry in a moment.", error_message); - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS)).await; attempts_after_failure += 1; continue; } } } - info!( + debug!( "Received an answer request. The ask_id is '{}'. The payload is '{}'", answer_request.ask_id, answer_request.payload ); @@ -241,6 +262,8 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { values.push(answer_request.payload); } + debug!("Completed the find request"); + Ok(tonic::Response::new(FindResponse { values })) } @@ -259,14 +282,14 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { info!("Received a get request for instance id {instance_id}"); // Retrieve the provider details. - let provider_endpoint_info_list = discover_digital_twin_providers_with_instance_id( - &self.invehicle_digital_twin_uri, - instance_id.as_str(), - digital_twin_protocol::GRPC, - &[digital_twin_operation::GET.to_string()], - ) - .await - .map_err(tonic::Status::internal)?; + let provider_endpoint_info_list = self + .discover_digital_twin_providers_with_instance_id( + instance_id.as_str(), + digital_twin_protocol::GRPC, + &[digital_twin_operation::GET.to_string()], + ) + .await + .map_err(tonic::Status::internal)?; info!("Found the provider endpoint info list: {provider_endpoint_info_list:?}"); @@ -308,16 +331,17 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { // Send the ask. let response = client.ask(request).await; if let Err(status) = response { - warn!("Unable to call ask, due to {status:?}\nWe will skip this one.."); + warn!("Unable to call ask, due to {status:?}\nWe will skip this one."); continue; } // Wait for the answer request. let mut answer_request: AnswerRequest = Default::default(); let mut attempts_after_failure = 0; - const MAX_ATTEMPTS_AFTER_FAILURE: u8 = 10; - while attempts_after_failure < MAX_ATTEMPTS_AFTER_FAILURE { - match timeout(Duration::from_secs(5), rx.recv()).await { + while attempts_after_failure < Self::MAX_RETRIES { + match timeout(Duration::from_millis(Self::TIMEOUT_PERIOD_IN_MILLIS), rx.recv()) + .await + { Ok(Ok(request)) => { if ask_id == request.ask_id { // We have received the answer request that we are expecting. @@ -332,13 +356,13 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { } Ok(Err(error_message)) => { warn!("Failed to receive the answer request. The error message is '{}'. We will retry in a moment.", error_message); - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS)).await; attempts_after_failure += 1; continue; } Err(error_message) => { warn!("Failed to receive the answer request. The error message is '{}'. We will retry in a moment.", error_message); - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(Self::BACKOFF_BASE_DURATION_IN_MILLIS)).await; attempts_after_failure += 1; continue; } @@ -389,14 +413,14 @@ impl DigitalTwinGraph for DigitalTwinGraphImpl { info!("Received an invoke request for instance id {instance_id}"); // Retrieve the provider details. - let provider_endpoint_info_list = discover_digital_twin_providers_with_instance_id( - &self.invehicle_digital_twin_uri, - instance_id.as_str(), - digital_twin_protocol::GRPC, - &[digital_twin_operation::INVOKE.to_string()], - ) - .await - .map_err(tonic::Status::internal)?; + let provider_endpoint_info_list = self + .discover_digital_twin_providers_with_instance_id( + instance_id.as_str(), + digital_twin_protocol::GRPC, + &[digital_twin_operation::INVOKE.to_string()], + ) + .await + .map_err(tonic::Status::internal)?; info!("Found the provider endpoint info list: {provider_endpoint_info_list:?}"); diff --git a/core/module/digital_twin_graph/src/digital_twin_graph_module.rs b/core/module/digital_twin_graph/src/digital_twin_graph_module.rs index 6959aaac..d4e7c3d9 100644 --- a/core/module/digital_twin_graph/src/digital_twin_graph_module.rs +++ b/core/module/digital_twin_graph/src/digital_twin_graph_module.rs @@ -5,11 +5,11 @@ use common::grpc_module::GrpcModule; use core_protobuf_data_access::async_rpc::v1::respond::respond_server::RespondServer; use core_protobuf_data_access::module::digital_twin_graph::v1::digital_twin_graph_server::DigitalTwinGraphServer; -// use log::{debug, error, info}; use std::sync::Arc; use tokio::sync::broadcast; use tonic::transport::server::RoutesBuilder; +use crate::digital_twin_graph_config; use crate::digital_twin_graph_impl::DigitalTwinGraphImpl; use crate::respond_impl::RespondImpl; @@ -30,11 +30,12 @@ impl GrpcModule for DigitalTwinGraphModule { /// # Arguments /// * `builder` - A tonic::RoutesBuilder that contains the grpc services to build. fn add_grpc_services(&self, builder: &mut RoutesBuilder) { - // Note: The authority is hardcoded for now, but it should be configurable in the future. - let invehicle_digital_twin_authority = "0.0.0.0:5010"; - let invehicle_digital_twin_uri = format!("http://{invehicle_digital_twin_authority}"); // Devskim: ignore DS137138 - let respond_authority = "0.0.0.0:5010"; - let respond_uri = format!("http://{respond_authority}"); // Devskim: ignore DS137138 + // Load the config. + let settings = digital_twin_graph_config::load_settings(); + let base_authority = settings.base_authority; + + let invehicle_digital_twin_uri = format!("http://{base_authority}"); // Devskim: ignore DS137138 + let respond_uri = format!("http://{base_authority}"); // Devskim: ignore DS137138 let (tx, _rx) = broadcast::channel(100); let tx = Arc::new(tx); diff --git a/core/module/digital_twin_graph/src/lib.rs b/core/module/digital_twin_graph/src/lib.rs index 030da7df..a17f09b7 100644 --- a/core/module/digital_twin_graph/src/lib.rs +++ b/core/module/digital_twin_graph/src/lib.rs @@ -2,6 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +pub mod digital_twin_graph_config; pub mod digital_twin_graph_impl; pub mod digital_twin_graph_module; pub mod respond_impl; diff --git a/core/module/digital_twin_graph/src/respond_impl.rs b/core/module/digital_twin_graph/src/respond_impl.rs index 169bf9a5..d4e9494b 100644 --- a/core/module/digital_twin_graph/src/respond_impl.rs +++ b/core/module/digital_twin_graph/src/respond_impl.rs @@ -4,7 +4,7 @@ use core_protobuf_data_access::async_rpc::v1::respond::respond_server::Respond; use core_protobuf_data_access::async_rpc::v1::respond::{AnswerRequest, AnswerResponse}; -use log::{debug, info}; +use log::debug; use std::sync::Arc; use tokio::sync::broadcast; @@ -17,7 +17,7 @@ impl RespondImpl { /// Create a new instance of a RespondImpl. /// /// # Arguments - /// * `tx` - The sender for the asynchronous channel for AnswerRequest's. + /// * `tx` - The sender for the asynchronous channel for AnswerRequests. pub fn new(tx: Arc>) -> RespondImpl { RespondImpl { tx } } @@ -33,14 +33,14 @@ impl Respond for RespondImpl { &self, request: tonic::Request, ) -> Result, tonic::Status> { - info!("Received an answer request"); + debug!("Received an answer request"); let tx = Arc::clone(&self.tx); // Send the request to the channel. if let Err(err_msg) = tx.send(request.into_inner()) { return Err(tonic::Status::internal(format!( - "Failed to send the answer request due to {err_msg}" + "Failed to send the answer request due to: {err_msg}" ))); } diff --git a/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.puml b/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.puml new file mode 100644 index 00000000..a8c43dd5 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.puml @@ -0,0 +1,30 @@ +@startuml + +component "Digital Twin Consumer" { +} + +component "Digital Twin App Server" { + component "Digital Twin Graph Service" { + interface "Digital Twin Graph Interface" + interface "Respond Interface" + } + component "Digital Twin Registry Service" { + interface "Digital Twin Registry Interface" + } +} + +component "Digital Twin Provider" { + interface "Request Interface" +} + +"Digital Twin Provider" -left-> "Digital Twin Registry Interface" : Register + +"Digital Twin Consumer" -right-> "Digital Twin Graph Interface" : Find/Get/Set/Invoke + +"Digital Twin Graph Service" -down-> "Digital Twin Registry Interface": FindByModelId + +"Digital Twin Graph Service" -right-> "Request Interface": Ask + +"Digital Twin Provider" -left-> "Respond Interface": Answer + +@enduml diff --git a/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.svg b/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.svg new file mode 100644 index 00000000..f4d4ee8a --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/digital_twin_graph_component.svg @@ -0,0 +1,43 @@ +Digital Twin App ServerDigital Twin Graph ServiceDigital Twin Registry ServiceDigital Twin ProviderDigital Twin ConsumerDigital Twin Graph InterfaceRespond InterfaceDigital Twin Registry InterfaceRequest InterfaceRegisterFind/Get/Set/InvokeFindByModelIdAskAnswer \ No newline at end of file diff --git a/docs/design/modules/digital_twin_graph/diagrams/find_sequence.puml b/docs/design/modules/digital_twin_graph/diagrams/find_sequence.puml new file mode 100644 index 00000000..4a9f01fb --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/find_sequence.puml @@ -0,0 +1,30 @@ +@startuml + +autonumber + +participant "Digital Twin Consumer" as CONSUMER +participant "Digital Twin Graph" as DIGITAL_TWIN_GRAPH +participant "Digital Twin Registry" as DIGITAL_TWIN_REGISTRY +participant "Digital Twin Provider" as PROVIDER + +CONSUMER -> DIGITAL_TWIN_GRAPH: Find(model_id: "dtmi:sdv:vehicle;1") - request + +DIGITAL_TWIN_GRAPH -> DIGITAL_TWIN_REGISTRY: FindByModeld(model_id: "dtmi:sdv:vehcile;1") - request +note right +end note +DIGITAL_TWIN_GRAPH <- DIGITAL_TWIN_REGISTRY: FindByModelId - response +note left +end note + +loop Iterate over the results from the FindByModelId call +DIGITAL_TWIN_GRAPH -> PROVIDER: Ask - Get +DIGITAL_TWIN_GRAPH -> PROVIDER: Ask - Get +DIGITAL_TWIN_GRAPH <- PROVIDER: Answer +DIGITAL_TWIN_GRAPH <- PROVIDER: Answer +end + +CONSUMER <- DIGITAL_TWIN_GRAPH: Find - response +note left +end note + +@enduml diff --git a/docs/design/modules/digital_twin_graph/diagrams/find_sequence.svg b/docs/design/modules/digital_twin_graph/diagrams/find_sequence.svg new file mode 100644 index 00000000..fb6ee844 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/find_sequence.svg @@ -0,0 +1,43 @@ +Digital Twin ConsumerDigital Twin ConsumerDigital Twin GraphDigital Twin GraphDigital Twin RegistryDigital Twin RegistryDigital Twin ProviderDigital Twin Provider1Find(model_id: "dtmi:sdv:vehicle;1") - request2FindByModeld(model_id: "dtmi:sdv:vehcile;1") - request3FindByModelId - responseloop[Iterate over the results from the FindByModelId call]4Ask - Get5Ask - Get6Answer7Answer8Find - response \ No newline at end of file diff --git a/docs/design/modules/digital_twin_graph/diagrams/get_sequence.puml b/docs/design/modules/digital_twin_graph/diagrams/get_sequence.puml new file mode 100644 index 00000000..71181723 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/get_sequence.puml @@ -0,0 +1,21 @@ +@startuml + +autonumber + +participant "Digital Twin Consumer" as CONSUMER +participant "Digital Twin Graph" as DIGITAL_TWIN_GRAPH +participant "Digital Twin Registry" as DIGITAL_TWIN_REGISTRY +participant "Digital Twin Provider" as PROVIDER + +CONSUMER -> DIGITAL_TWIN_GRAPH: Get(instance_id: "1234567890", member_path: "vehicle_identification") - request + +DIGITAL_TWIN_GRAPH -> DIGITAL_TWIN_REGISTRY: FindByInstanceId(instance_id: "1234567890") - request +DIGITAL_TWIN_GRAPH <- DIGITAL_TWIN_REGISTRY: FindByInstanceId - response + +DIGITAL_TWIN_GRAPH -> PROVIDER: Ask - Get + +DIGITAL_TWIN_GRAPH <- PROVIDER: Answer + +CONSUMER <- DIGITAL_TWIN_GRAPH: Get - response + +@enduml diff --git a/docs/design/modules/digital_twin_graph/diagrams/get_sequence.svg b/docs/design/modules/digital_twin_graph/diagrams/get_sequence.svg new file mode 100644 index 00000000..319a00e1 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/get_sequence.svg @@ -0,0 +1,34 @@ +Digital Twin ConsumerDigital Twin ConsumerDigital Twin GraphDigital Twin GraphDigital Twin RegistryDigital Twin RegistryDigital Twin ProviderDigital Twin Provider1Get(instance_id: "1234567890", member_path: "vehicle_identification") - request2FindByInstanceId(instance_id: "1234567890") - request3FindByInstanceId - response4Ask - Get5Answer6Get - response \ No newline at end of file diff --git a/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.puml b/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.puml new file mode 100644 index 00000000..6d9148d9 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.puml @@ -0,0 +1,20 @@ +@startuml + +autonumber + +participant "Digital Twin Consumer" as CONSUMER +participant "Digital Twin Graph" as DIGITAL_TWIN_GRAPH +participant "Digital Twin Registry" as DIGITAL_TWIN_REGISTRY +participant "Digital Twin Provider" as PROVIDER + +CONSUMER -> DIGITAL_TWIN_GRAPH: Invoke(instance_id: "1234567890", payload: "") - request + +DIGITAL_TWIN_GRAPH -> DIGITAL_TWIN_REGISTRY: FindByInstanceId(id: "1234567890") - request +DIGITAL_TWIN_GRAPH <- DIGITAL_TWIN_REGISTRY: FindByInstanceId - response + +DIGITAL_TWIN_GRAPH -> PROVIDER: Ask - request +DIGITAL_TWIN_GRAPH <- PROVIDER: Answer + +CONSUMER <- DIGITAL_TWIN_GRAPH: Invoke - response + +@enduml diff --git a/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.svg b/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.svg new file mode 100644 index 00000000..29744015 --- /dev/null +++ b/docs/design/modules/digital_twin_graph/diagrams/invoke_sequence.svg @@ -0,0 +1,33 @@ +Digital Twin ConsumerDigital Twin ConsumerDigital Twin GraphDigital Twin GraphDigital Twin RegistryDigital Twin RegistryDigital Twin ProviderDigital Twin Provider1Invoke(instance_id: "1234567890", payload: "") - request2FindByInstanceId(id: 1234567890") - request3FindByInstanceId - response4Ask - request5Answer6Invoke - response \ No newline at end of file