From 976400e39361389d8bfd703952ed972d6f7637c8 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 18 May 2023 16:38:21 -0700 Subject: [PATCH 01/23] Use Chariott --- .gitmodules | 6 ++++++ Cargo.toml | 1 + core/protobuf_data_access/Cargo.toml | 1 + core/protobuf_data_access/build.rs | 10 ++++++++++ core/protobuf_data_access/src/lib.rs | 19 +++++++++++++++++++ external/chariott | 1 + samples/protobuf_data_access/Cargo.toml | 1 + samples/protobuf_data_access/build.rs | 10 ++++++++++ samples/protobuf_data_access/src/lib.rs | 18 ++++++++++++++++++ 9 files changed, 67 insertions(+) create mode 160000 external/chariott diff --git a/.gitmodules b/.gitmodules index 541b2bfe..c0347573 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "external/iot-plugandplay-models"] path = external/iot-plugandplay-models url = https://github.com/Azure/iot-plugandplay-models +[submodule "external/--force"] + path = external/--force + url = https://github.com/eclipse-chariott/chariott +[submodule "external/chariott"] + path = external/chariott + url = https://github.com/eclipse-chariott/chariott diff --git a/Cargo.toml b/Cargo.toml index 9d3e4c6b..a3ea1f6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ lazy_static = "1.4.0" log = "^0.4" parking_lot = "0.12.1" prost = "0.11" +prost-types = "0.11" regex = " 1.8.1" tokio = "1.0" tonic = "0.9.2" diff --git a/core/protobuf_data_access/Cargo.toml b/core/protobuf_data_access/Cargo.toml index 2680dfcb..f97cef5f 100644 --- a/core/protobuf_data_access/Cargo.toml +++ b/core/protobuf_data_access/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] prost = { workspace = true } +prost-types = { workspace = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/core/protobuf_data_access/build.rs b/core/protobuf_data_access/build.rs index 5629ce30..2255067b 100644 --- a/core/protobuf_data_access/build.rs +++ b/core/protobuf_data_access/build.rs @@ -10,6 +10,16 @@ fn main() -> Result<(), Box> { &["../../interfaces/digital_twin/v1/digital_twin.proto"], &["../../interfaces/digital_twin/v1/"], )?; + tonic_build::configure() + .compile( + &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], + &["../../external/chariott/proto"], + )?; + tonic_build::configure() + .compile( + &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], + &["../../external/chariott/proto"], + )?; Ok(()) } diff --git a/core/protobuf_data_access/src/lib.rs b/core/protobuf_data_access/src/lib.rs index d8ea014d..fa204526 100644 --- a/core/protobuf_data_access/src/lib.rs +++ b/core/protobuf_data_access/src/lib.rs @@ -7,3 +7,22 @@ pub mod digital_twin { tonic::include_proto!("digital_twin"); } } + +pub mod chariott { + pub mod common { + pub mod v1 { + tonic::include_proto!("chariott.common.v1"); + } + } + pub mod provider { + pub mod v1 { + tonic::include_proto!("chariott.provider.v1"); + } + } + pub mod runtime { + pub mod v1 { + tonic::include_proto!("chariott.runtime.v1"); + } + } +} + diff --git a/external/chariott b/external/chariott new file mode 160000 index 00000000..57e3a550 --- /dev/null +++ b/external/chariott @@ -0,0 +1 @@ +Subproject commit 57e3a550da19e0442dc7effdf13c728326e9bdc5 diff --git a/samples/protobuf_data_access/Cargo.toml b/samples/protobuf_data_access/Cargo.toml index cb0f0f82..89e9b75a 100644 --- a/samples/protobuf_data_access/Cargo.toml +++ b/samples/protobuf_data_access/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT" [dependencies] tonic = { workspace = true } prost = { workspace = true } +prost-types = { workspace = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/samples/protobuf_data_access/build.rs b/samples/protobuf_data_access/build.rs index 6b3aeb15..d69f6596 100644 --- a/samples/protobuf_data_access/build.rs +++ b/samples/protobuf_data_access/build.rs @@ -12,6 +12,16 @@ fn main() -> Result<(), Box> { &["../../interfaces/digital_twin/v1/digital_twin.proto"], &["../../interfaces/digital_twin/v1/"], )?; + tonic_build::configure() + .compile( + &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], + &["../../external/chariott/proto"], + )?; + tonic_build::configure() + .compile( + &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], + &["../../external/chariott/proto"], + )?; Ok(()) } diff --git a/samples/protobuf_data_access/src/lib.rs b/samples/protobuf_data_access/src/lib.rs index 23c61b49..2606f5e0 100644 --- a/samples/protobuf_data_access/src/lib.rs +++ b/samples/protobuf_data_access/src/lib.rs @@ -8,6 +8,24 @@ pub mod digital_twin { } } +pub mod chariott { + pub mod common { + pub mod v1 { + tonic::include_proto!("chariott.common.v1"); + } + } + pub mod provider { + pub mod v1 { + tonic::include_proto!("chariott.provider.v1"); + } + } + pub mod runtime { + pub mod v1 { + tonic::include_proto!("chariott.runtime.v1"); + } + } +} + pub mod sample_grpc { pub mod v1 { pub mod digital_twin_consumer { From 266cc25946ea0839b9b8cbf8b1b145f97b4647ae Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 22 May 2023 16:19:53 -0700 Subject: [PATCH 02/23] Use Chariott --- Cargo.toml | 1 + core/in-vehicle-digital-twin/Cargo.toml | 1 + core/in-vehicle-digital-twin/src/main.rs | 58 +++++- .../src/providerservice_impl.rs | 170 ++++++++++++++++++ samples/common/src/lib.rs | 52 +++++- samples/property/consumer/src/main.rs | 18 +- samples/property/provider/src/main.rs | 6 +- 7 files changed, 294 insertions(+), 12 deletions(-) create mode 100644 core/in-vehicle-digital-twin/src/providerservice_impl.rs diff --git a/Cargo.toml b/Cargo.toml index a3ea1f6c..649085c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,4 +42,5 @@ serde = "1.0.160" serde_json = "^1.0" strum = "0.24" strum_macros = "0.24" +url = "2.3.1" uuid = "1.2.2" diff --git a/core/in-vehicle-digital-twin/Cargo.toml b/core/in-vehicle-digital-twin/Cargo.toml index 8624f889..73762cdb 100644 --- a/core/in-vehicle-digital-twin/Cargo.toml +++ b/core/in-vehicle-digital-twin/Cargo.toml @@ -20,6 +20,7 @@ core-protobuf-data-access = { path = "../protobuf_data_access" } serde_json = { workspace = true } tokio = { workspace = true , features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } +url = { workspace = true } [build-dependencies] tonic-build = { workspace = true } \ No newline at end of file diff --git a/core/in-vehicle-digital-twin/src/main.rs b/core/in-vehicle-digital-twin/src/main.rs index 7385f71a..449ed1b0 100644 --- a/core/in-vehicle-digital-twin/src/main.rs +++ b/core/in-vehicle-digital-twin/src/main.rs @@ -3,17 +3,59 @@ // SPDX-License-Identifier: MIT use core_protobuf_data_access::digital_twin::v1::digital_twin_server::DigitalTwinServer; +use core_protobuf_data_access::chariott::provider::v1::provider_service_server::ProviderServiceServer; +use core_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; +use core_protobuf_data_access::chariott::runtime::v1::{intent_registration, IntentRegistration, intent_service_registration, IntentServiceRegistration, RegisterRequest}; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::RwLock; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; +use tonic::{Request, Status}; use tonic::transport::Server; +use url::Url; mod digitaltwin_impl; +mod providerservice_impl; -const IN_VEHICLE_DIGITAL_TWIN_ADDR: &str = "[::1]:50010"; +const IN_VEHICLE_DIGITAL_TWIN_AUTHORITY: &str = "0.0.0.0:5010"; + +pub async fn register_ibeji_services_with_chariott(digital_twin_url: &str) -> Result<(), Status> { + + let chariott_url = "http://0.0.0.0:4243"; + + let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; + + let service = Some(IntentServiceRegistration { + name: "digital-twin".to_string(), + version: "1.0".to_string(), + url: digital_twin_url.to_string(), + locality: intent_service_registration::ExecutionLocality::Local as i32, + }); + + let intents = vec![ + IntentRegistration { + namespace: "sdv.ibeji".to_string(), + intent: intent_registration::Intent::Discover as i32, + }, + ]; + + let request = Request::new(RegisterRequest { + service, + intents, + }); + + let response = client.register(request).await; + + if !response.is_ok() { + return Err(Status::internal("Chariott register request failed")); + } + + info!("{:?}", response.unwrap().into_inner()); + + return Ok(()) +} #[tokio::main] async fn main() -> Result<(), Box> { @@ -23,13 +65,21 @@ async fn main() -> Result<(), Box> { info!("The In-Vehicle Digital Twin Service has started."); // Setup the HTTP server. - let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_ADDR.parse()?; + let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_AUTHORITY.parse()?; let digitaltwin_impl = digitaltwin_impl::DigitalTwinImpl { entity_access_info_map: Arc::new(RwLock::new(HashMap::new())), }; + let in_vehicle_digital_twin_address = format!("http://{IN_VEHICLE_DIGITAL_TWIN_AUTHORITY}"); // Devskim: ignore DS137138 + let in_vehicle_digital_twin_url = Url::parse(&in_vehicle_digital_twin_address)?; + let providerservice_impl = providerservice_impl::ProviderServiceImpl::new(in_vehicle_digital_twin_url); let server_future = - Server::builder().add_service(DigitalTwinServer::new(digitaltwin_impl)).serve(addr); - info!("The HTTP server is listening on address '{IN_VEHICLE_DIGITAL_TWIN_ADDR}'"); + Server::builder() + .add_service(DigitalTwinServer::new(digitaltwin_impl)) + .add_service(ProviderServiceServer::new(providerservice_impl)) + .serve(addr); + info!("The HTTP server is listening on address '{in_vehicle_digital_twin_address}'"); + + register_ibeji_services_with_chariott(&in_vehicle_digital_twin_address).await?; server_future.await?; diff --git a/core/in-vehicle-digital-twin/src/providerservice_impl.rs b/core/in-vehicle-digital-twin/src/providerservice_impl.rs new file mode 100644 index 00000000..fa77dc84 --- /dev/null +++ b/core/in-vehicle-digital-twin/src/providerservice_impl.rs @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +// extern crate iref; + +// use core_protobuf_data_access::chariott::common::v1::Fulfillment; +/* +use core_protobuf_data_access::chariott::provider::v1::provider_service_server::ProviderService; +use core_protobuf_data_access::chariott::provider::v1::{ + FulfillRequest, FulfillResponse, +}; +use log::info; +*/ + +use core_protobuf_data_access::chariott::{ + common::v1::{ + discover_fulfillment::Service, DiscoverFulfillment, fulfillment::Fulfillment as FulfillmentEnum, + Fulfillment as FulfillmentMessage, intent::Intent as IntentEnum, + }, + provider::v1::{provider_service_server::ProviderService, FulfillRequest, FulfillResponse}, +}; +use log::info; +use std::collections::HashMap; +use tonic::{Request, Response, Status}; +use url::Url; + +#[derive(Debug)] +pub struct ProviderServiceImpl { + pub url: Url, +} + +#[tonic::async_trait] +impl ProviderService for ProviderServiceImpl { + /// Fulfill implementation. + /// + /// # Arguments + /// * `request` - Fulfill request. + async fn fulfill( + &self, + request: Request, + ) -> Result, Status> { + info!("Received a fulfill request"); + let fulfillment = match request + .into_inner() + .intent + .and_then(|i| i.intent) + .ok_or_else(|| Status::invalid_argument("Intent must be specified."))? + { + IntentEnum::Discover(_intent) => Ok(FulfillmentEnum::Discover(DiscoverFulfillment { + services: vec![Service { + url: self.url.to_string(), + schema_kind: "grpc+proto".to_owned(), + schema_reference: "example.provider.v1".to_owned(), + metadata: HashMap::new(), + }], + })), + _ => Err(Status::unknown("Unsupported or unknown intent."))?, + }; + + fulfillment.map(|f| { + Response::new(FulfillResponse { + fulfillment: Some(FulfillmentMessage { fulfillment: Some(f) }), + }) + }) + } +} + +impl ProviderServiceImpl { + pub fn new(url: Url) -> Self { + Self { url } + } +} + +#[cfg(test)] +mod providerservice_impl_tests { + use super::*; + // use core_protobuf_data_access::digital_twin::v1::EndpointInfo; + +/* + #[tokio::test] + async fn find_by_id_test() { + let operations = vec![String::from("Subscribe"), String::from("Unsubscribe")]; + + let endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + operations, + }; + + let entity_access_info = EntityAccessInfo { + name: String::from("AmbientAirTemperature"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + description: String::from("Ambient air temperature"), + endpoint_info_list: vec![endpoint_info], + }; + + let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); + + let digital_twin_impl = + DigitalTwinImpl { entity_access_info_map: entity_access_info_map.clone() }; + + // This block controls the lifetime of the lock. + { + let mut lock: RwLockWriteGuard> = + entity_access_info_map.write(); + lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); + } + + let request = tonic::Request::new(FindByIdRequest { + id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + }); + let result = digital_twin_impl.find_by_id(request).await; + assert!(result.is_ok()); + let response = result.unwrap(); + let response_inner = response.into_inner(); + + assert!(response_inner.entity_access_info.is_some()); + + let response_entity_access_info = response_inner.entity_access_info.unwrap(); + + assert_eq!( + response_entity_access_info.id, + "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" + ); + assert_eq!(response_entity_access_info.endpoint_info_list.len(), 1); + assert_eq!( + response_entity_access_info.endpoint_info_list[0].uri, + "http://[::1]:40010" // Devskim: ignore DS137138 + ); + } + + #[tokio::test] + async fn register_test() { + let endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], + }; + + let entity_access_info = EntityAccessInfo { + name: String::from("AmbientAirTemperature"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + description: String::from("Ambient air temperature"), + endpoint_info_list: vec![endpoint_info], + }; + + let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); + + let digital_twin_impl = + DigitalTwinImpl { entity_access_info_map: entity_access_info_map.clone() }; + + let request = tonic::Request::new(RegisterRequest { + entity_access_info_list: vec![entity_access_info], + }); + let result = digital_twin_impl.register(request).await; + assert!(result.is_ok(), "register result is not okay: {result:?}"); + + // This block controls the lifetime of the lock. + { + let lock: RwLockReadGuard> = + entity_access_info_map.read(); + // Make sure that we populated the entity map from the contents of the DTDL. + assert_eq!(lock.len(), 1, "expected length was 1, actual length is {}", lock.len()); + } + } +*/ +} diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 84421d40..ae60636b 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -3,8 +3,20 @@ // SPDX-License-Identifier: MIT use log::{debug, info}; +use samples_protobuf_data_access::chariott::{ + common::v1::{ + discover_fulfillment, + DiscoverIntent, + fulfillment::Fulfillment as FulfillmentEnum, + intent::Intent as IntentEnum, + Intent as IntentMessage, + }, + runtime::v1::{FulfillRequest}, +}; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdRequest}; +use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; +use tonic::{Request, Status}; /// Supported digital twin operations. pub mod digital_twin_operation { @@ -39,7 +51,7 @@ pub fn is_subset(subset: &[String], superset: &[String]) -> bool { /// `protocol` - The required protocol. /// `operations` - The required operations. pub async fn find_provider_endpoint( - in_vehicle_digitial_twin_servuce_uri: &'static str, + in_vehicle_digitial_twin_servuce_uri: &'static str, entity_id: &str, protocol: &str, operations: &[String], @@ -78,6 +90,44 @@ pub async fn find_provider_endpoint( Ok(result) } +pub async fn discover_digital_twin_services_using_chariott() -> Result, Status> { + + let chariott_url = "http://0.0.0.0:4243"; + + let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; + + let request = Request::new(FulfillRequest { + namespace: "sdv.ibeji".to_string(), + intent: Some(IntentMessage { + intent: Some(IntentEnum::Discover(DiscoverIntent {})), + }), + }); + + // Get list of services at the requested namespace, if any. + let services: Option> = client + .fulfill(request) + .await? + .into_inner() + .fulfillment + .and_then(|fulfillment_message| fulfillment_message.fulfillment) + .and_then(|fulfillment_enum| match fulfillment_enum { + FulfillmentEnum::Discover(discover) => { + Some(discover.services.into_iter().collect()) + } + _ => None, + }); + + if services.is_some() { + for service in services.unwrap() { + if service.schema_kind == "grpc+proto" { + return Ok(Some(service.url.to_string())) + } + } + } + + Ok(None) +} + #[cfg(test)] mod ibeji_common_tests { use super::*; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 781a2285..b1072fd7 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -5,7 +5,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; +use samples_common::{digital_twin_operation, digital_twin_protocol, discover_digital_twin_services_using_chariott, find_provider_endpoint}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::SubscribeRequest; @@ -14,9 +14,9 @@ use tonic::transport::Server; mod consumer_impl; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 +// const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const CONSUMER_AUTHORITY: &str = "[::1]:60010"; +const CONSUMER_AUTHORITY: &str = "0.0.0.0:6010"; #[tokio::main] async fn main() -> Result<(), Box> { @@ -32,8 +32,18 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); + let url_option = discover_digital_twin_services_using_chariott().await?; + if url_option.is_none() { + return Err("Failed to discover the in-vehicle digital twin service's URL")?; + } + + let url = url_option.unwrap().clone(); + + // Workarounhd: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str + let static_url_str = Box::leak(url.into_boxed_str()); + let provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + static_url_str, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 7e00373c..b9a1fd62 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -22,8 +22,8 @@ use tonic::transport::Server; use crate::provider_impl::{ProviderImpl, SubscriptionMap}; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const PROVIDER_AUTHORITY: &str = "[::1]:40010"; +const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://0.0.0.0:5010"; // Devskim: ignore DS137138 +const PROVIDER_AUTHORITY: &str = "0.0.0.0:4010"; /// Start the ambient air temperature data stream. /// @@ -107,7 +107,7 @@ async fn main() -> Result<(), Box> { digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::UNSUBSCRIBE.to_string(), ], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 + uri: "http://0.0.0.0:4010".to_string(), // Devskim: ignore DS137138 context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), }; From cd2139e47b7c9c25f6a6f075717a7d8eed0a3e21 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 29 May 2023 17:31:20 -0700 Subject: [PATCH 03/23] Use Chariott --- Cargo.toml | 7 +- .../Cargo.toml | 12 +- .../src/digitaltwin_impl.rs | 0 .../src/invehicle_digital_twin_config.rs | 25 +++ .../src/main.rs | 30 ++-- .../src/providerservice_impl.rs | 0 .../dtdl/v2/content/sdv/vehicle.json | 4 +- samples/command/consumer/src/main.rs | 3 +- samples/command/provider/src/main.rs | 2 +- samples/common/Cargo.toml | 10 +- samples/common/src/constants.rs | 17 ++ samples/common/src/consumer_config.rs | 26 +++ samples/common/src/lib.rs | 155 +----------------- samples/common/src/misc.rs | 141 ++++++++++++++++ samples/common/src/provider_config.rs | 26 +++ samples/mixed/consumer/src/main.rs | 3 +- samples/mixed/provider/src/main.rs | 2 +- samples/property/Cargo.toml | 3 +- samples/property/consumer/src/main.rs | 48 ++++-- samples/property/provider/src/main.rs | 2 +- 20 files changed, 331 insertions(+), 185 deletions(-) rename core/{in-vehicle-digital-twin => invehicle-digital-twin}/Cargo.toml (72%) rename core/{in-vehicle-digital-twin => invehicle-digital-twin}/src/digitaltwin_impl.rs (100%) create mode 100644 core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs rename core/{in-vehicle-digital-twin => invehicle-digital-twin}/src/main.rs (68%) rename core/{in-vehicle-digital-twin => invehicle-digital-twin}/src/providerservice_impl.rs (100%) create mode 100644 samples/common/src/constants.rs create mode 100644 samples/common/src/consumer_config.rs create mode 100644 samples/common/src/misc.rs create mode 100644 samples/common/src/provider_config.rs diff --git a/Cargo.toml b/Cargo.toml index 649085c3..e74a759c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ # core "core/protobuf_data_access", - "core/in-vehicle-digital-twin", + "core/invehicle-digital-twin", # digital twin model "digital-twin-model", @@ -25,6 +25,7 @@ members = [ [workspace.dependencies] async-std = "^1.5" +config = "0.13.3" env_logger= "0.10.0" futures = "0.3" generic-json = "^0.7" @@ -34,13 +35,15 @@ log = "^0.4" parking_lot = "0.12.1" prost = "0.11" prost-types = "0.11" -regex = " 1.8.1" +regex = " 1.8.2" tokio = "1.0" tonic = "0.9.2" tonic-build = "0.9.2" serde = "1.0.160" +serde_derive = "1.0.163" serde_json = "^1.0" strum = "0.24" strum_macros = "0.24" url = "2.3.1" uuid = "1.2.2" +yaml-rust = "0.4" diff --git a/core/in-vehicle-digital-twin/Cargo.toml b/core/invehicle-digital-twin/Cargo.toml similarity index 72% rename from core/in-vehicle-digital-twin/Cargo.toml rename to core/invehicle-digital-twin/Cargo.toml index 73762cdb..01fb29ac 100644 --- a/core/in-vehicle-digital-twin/Cargo.toml +++ b/core/invehicle-digital-twin/Cargo.toml @@ -3,13 +3,14 @@ # SPDX-License-Identifier: MIT [package] -name = "in-vehicle-digital-twin" +name = "invehicle-digital-twin" version = "0.1.0" edition = "2021" license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } +config = { workspace = true } env_logger= { workspace = true } iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } @@ -17,10 +18,17 @@ log = { workspace = true } parking_lot = { workspace = true } prost = { workspace = true } core-protobuf-data-access = { path = "../protobuf_data_access" } +serde = { workspace = true, features = ["derive"] } +serde_derive = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true , features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } url = { workspace = true } +yaml-rust = { workspace = true, optional = true } [build-dependencies] -tonic-build = { workspace = true } \ No newline at end of file +tonic-build = { workspace = true } + +[features] +default = ["yaml"] +yaml = ["yaml-rust"] \ No newline at end of file diff --git a/core/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/core/invehicle-digital-twin/src/digitaltwin_impl.rs similarity index 100% rename from core/in-vehicle-digital-twin/src/digitaltwin_impl.rs rename to core/invehicle-digital-twin/src/digitaltwin_impl.rs diff --git a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs new file mode 100644 index 00000000..96e42b2c --- /dev/null +++ b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +#![cfg(feature = "yaml")] + +use serde_derive::Deserialize; +use config::{Config, File, FileFormat}; + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub invehicle_digital_twin_authority: String, + pub chariott_url: Option, +} + +pub fn load_settings() -> Settings { + let config = Config::builder() + .add_source(File::new("invehicle_digital_twin_settings", FileFormat::Yaml)) + .build() + .unwrap(); + + let settings: Settings = config.try_deserialize().unwrap(); + + settings +} diff --git a/core/in-vehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs similarity index 68% rename from core/in-vehicle-digital-twin/src/main.rs rename to core/invehicle-digital-twin/src/main.rs index 449ed1b0..152e4a8e 100644 --- a/core/in-vehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -16,21 +16,23 @@ use tonic::{Request, Status}; use tonic::transport::Server; use url::Url; +// use crate::invehicle_digital_twin_config::load_settings; + mod digitaltwin_impl; +mod invehicle_digital_twin_config; mod providerservice_impl; -const IN_VEHICLE_DIGITAL_TWIN_AUTHORITY: &str = "0.0.0.0:5010"; - -pub async fn register_ibeji_services_with_chariott(digital_twin_url: &str) -> Result<(), Status> { +// const INVEHICLE_DIGITAL_TWIN_AUTHORITY: &str = "0.0.0.0:5010"; - let chariott_url = "http://0.0.0.0:4243"; +pub async fn register_ibeji_services_with_chariott(chariott_url: &str, invehicle_digital_twin_url: &str) -> Result<(), Status> { + // let chariott_url = "http://0.0.0.0:4243"; let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; let service = Some(IntentServiceRegistration { name: "digital-twin".to_string(), version: "1.0".to_string(), - url: digital_twin_url.to_string(), + url: invehicle_digital_twin_url.to_string(), locality: intent_service_registration::ExecutionLocality::Local as i32, }); @@ -64,22 +66,28 @@ async fn main() -> Result<(), Box> { info!("The In-Vehicle Digital Twin Service has started."); + let settings = invehicle_digital_twin_config::load_settings(); + let invehicle_digital_twin_authority = settings.invehicle_digital_twin_authority; + let chariott_url_option = settings.chariott_url; + // Setup the HTTP server. - let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_AUTHORITY.parse()?; + let addr: SocketAddr = invehicle_digital_twin_authority.parse()?; let digitaltwin_impl = digitaltwin_impl::DigitalTwinImpl { entity_access_info_map: Arc::new(RwLock::new(HashMap::new())), }; - let in_vehicle_digital_twin_address = format!("http://{IN_VEHICLE_DIGITAL_TWIN_AUTHORITY}"); // Devskim: ignore DS137138 - let in_vehicle_digital_twin_url = Url::parse(&in_vehicle_digital_twin_address)?; - let providerservice_impl = providerservice_impl::ProviderServiceImpl::new(in_vehicle_digital_twin_url); + let invehicle_digital_twin_address = format!("http://{invehicle_digital_twin_authority}"); // Devskim: ignore DS137138 + let invehicle_digital_twin_url = Url::parse(&invehicle_digital_twin_address)?; + let providerservice_impl = providerservice_impl::ProviderServiceImpl::new(invehicle_digital_twin_url); let server_future = Server::builder() .add_service(DigitalTwinServer::new(digitaltwin_impl)) .add_service(ProviderServiceServer::new(providerservice_impl)) .serve(addr); - info!("The HTTP server is listening on address '{in_vehicle_digital_twin_address}'"); + info!("The HTTP server is listening on address '{invehicle_digital_twin_address}'"); - register_ibeji_services_with_chariott(&in_vehicle_digital_twin_address).await?; + if chariott_url_option.is_some() { + register_ibeji_services_with_chariott(&chariott_url_option.unwrap(), &invehicle_digital_twin_address).await?; + } server_future.await?; diff --git a/core/in-vehicle-digital-twin/src/providerservice_impl.rs b/core/invehicle-digital-twin/src/providerservice_impl.rs similarity index 100% rename from core/in-vehicle-digital-twin/src/providerservice_impl.rs rename to core/invehicle-digital-twin/src/providerservice_impl.rs diff --git a/digital-twin-model/dtdl/v2/content/sdv/vehicle.json b/digital-twin-model/dtdl/v2/content/sdv/vehicle.json index adbe2685..f4e1fb9f 100644 --- a/digital-twin-model/dtdl/v2/content/sdv/vehicle.json +++ b/digital-twin-model/dtdl/v2/content/sdv/vehicle.json @@ -51,10 +51,10 @@ "request": { "name": "ShowNotification", "displayName": "Show Notification", - "descriptiption": "Show a notification on the HMI.", + "description": "Show a notification on the HMI.", "schema": "string" } } ] } -] \ No newline at end of file +] diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index e6351857..0c60488a 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -7,7 +7,8 @@ mod consumer_impl; use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::find_provider_endpoint; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::InvokeRequest; diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 4ad01769..8df94415 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; -use samples_common::{digital_twin_operation, digital_twin_protocol}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; diff --git a/samples/common/Cargo.toml b/samples/common/Cargo.toml index e5d33cb7..8a272d2a 100644 --- a/samples/common/Cargo.toml +++ b/samples/common/Cargo.toml @@ -9,6 +9,14 @@ edition = "2021" license = "MIT" [dependencies] +config = { workspace = true } log = { workspace = true } samples-protobuf-data-access = { path = "../protobuf_data_access" } -tonic = { workspace = true } \ No newline at end of file +serde = { workspace = true, features = ["derive"] } +serde_derive = { workspace = true } +tonic = { workspace = true } +yaml-rust = { workspace = true, optional = true } + +[features] +default = ["yaml"] +yaml = ["yaml-rust"] diff --git a/samples/common/src/constants.rs b/samples/common/src/constants.rs new file mode 100644 index 00000000..5fccfcf7 --- /dev/null +++ b/samples/common/src/constants.rs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +/// Supported digital twin operations. +pub mod digital_twin_operation { + pub const GET: &str = "Get"; + pub const SET: &str = "Set"; + pub const SUBSCRIBE: &str = "Subscribe"; + pub const UNSUBSCRIBE: &str = "Unsubscribe"; + pub const INVOKE: &str = "Invoke"; +} + +// Supported gitial twin protocols. +pub mod digital_twin_protocol { + pub const GRPC: &str = "grpc"; +} diff --git a/samples/common/src/consumer_config.rs b/samples/common/src/consumer_config.rs new file mode 100644 index 00000000..d1a18985 --- /dev/null +++ b/samples/common/src/consumer_config.rs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +#![cfg(feature = "yaml")] + +use serde_derive::Deserialize; +use config::{Config, File, FileFormat}; + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub consumer_authority: String, + pub chariott_url: Option, + pub invehicle_digital_twin_url: Option, +} + +pub fn load_settings() -> Settings { + let config = Config::builder() + .add_source(File::new("consumer_settings", FileFormat::Yaml)) + .build() + .unwrap(); + + let settings: Settings = config.try_deserialize().unwrap(); + + settings +} diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index ae60636b..fffb294d 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -2,154 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -use log::{debug, info}; -use samples_protobuf_data_access::chariott::{ - common::v1::{ - discover_fulfillment, - DiscoverIntent, - fulfillment::Fulfillment as FulfillmentEnum, - intent::Intent as IntentEnum, - Intent as IntentMessage, - }, - runtime::v1::{FulfillRequest}, -}; -use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; -use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdRequest}; -use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; -use tonic::{Request, Status}; - -/// Supported digital twin operations. -pub mod digital_twin_operation { - pub const GET: &str = "Get"; - pub const SET: &str = "Set"; - pub const SUBSCRIBE: &str = "Subscribe"; - pub const UNSUBSCRIBE: &str = "Unsubscribe"; - pub const INVOKE: &str = "Invoke"; -} - -// Supported gitial twin protocols. -pub mod digital_twin_protocol { - pub const GRPC: &str = "grpc"; -} - -/// Is the provided subset a subset of the provided superset? -/// -/// # Arguments -/// `subset` - The provided subset. -/// `superset` - The provided superset. -pub fn is_subset(subset: &[String], superset: &[String]) -> bool { - subset.iter().all(|subset_member| { - superset.iter().any(|supserset_member| subset_member == supserset_member) - }) -} - -/// Find a provider endpoint that satifies the requirements. -/// -/// # Arguments -/// `in_vehcile_digitial_twin_servuce_uri` - iI-vehicle digital twin service URI. -/// `entity_id` - The matching entity id. -/// `protocol` - The required protocol. -/// `operations` - The required operations. -pub async fn find_provider_endpoint( - in_vehicle_digitial_twin_servuce_uri: &'static str, - entity_id: &str, - protocol: &str, - operations: &[String], -) -> Result { - info!("Sending a find_by_id request for entity id {entity_id} to the In-Vehicle Digital Twin Service URI {in_vehicle_digitial_twin_servuce_uri}"); - let mut client = DigitalTwinClient::connect(in_vehicle_digitial_twin_servuce_uri) - .await - .map_err(|error| format!("{error}"))?; - let request = tonic::Request::new(FindByIdRequest { id: entity_id.to_string() }); - let response = client.find_by_id(request).await.map_err(|error| error.to_string())?; - let response_inner = response.into_inner(); - debug!("Received the response for the find_by_id request"); - info!("response_payload: {:?}", response_inner.entity_access_info); - - let entity_access_info = response_inner.entity_access_info.expect("Did not find the entity"); - - let mut matching_endpoint_info_option: Option = None; - for endpoint_info in entity_access_info.endpoint_info_list { - // We require and endpoint that supports the protocol and supports all of the operations. - if endpoint_info.protocol == protocol - && is_subset(operations, endpoint_info.operations.as_slice()) - { - matching_endpoint_info_option = Some(endpoint_info); - break; - } - } - - if matching_endpoint_info_option.is_none() { - return Err("Did not find an endpoint that met our requirements".to_string()); - } - - let result = matching_endpoint_info_option.unwrap(); - - info!("Found a matching endpoint for entity id {entity_id} that has URI {}", result.uri); - - Ok(result) -} - -pub async fn discover_digital_twin_services_using_chariott() -> Result, Status> { - - let chariott_url = "http://0.0.0.0:4243"; - - let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; - - let request = Request::new(FulfillRequest { - namespace: "sdv.ibeji".to_string(), - intent: Some(IntentMessage { - intent: Some(IntentEnum::Discover(DiscoverIntent {})), - }), - }); - - // Get list of services at the requested namespace, if any. - let services: Option> = client - .fulfill(request) - .await? - .into_inner() - .fulfillment - .and_then(|fulfillment_message| fulfillment_message.fulfillment) - .and_then(|fulfillment_enum| match fulfillment_enum { - FulfillmentEnum::Discover(discover) => { - Some(discover.services.into_iter().collect()) - } - _ => None, - }); - - if services.is_some() { - for service in services.unwrap() { - if service.schema_kind == "grpc+proto" { - return Ok(Some(service.url.to_string())) - } - } - } - - Ok(None) -} - -#[cfg(test)] -mod ibeji_common_tests { - use super::*; - - #[test] - fn is_subset_test() { - assert!(is_subset(&[], &[])); - assert!(is_subset(&[], &["one".to_string()])); - assert!(is_subset(&[], &["one".to_string(), "two".to_string()])); - assert!(is_subset(&["one".to_string()], &["one".to_string(), "two".to_string()])); - assert!(is_subset( - &["one".to_string(), "two".to_string()], - &["one".to_string(), "two".to_string()] - )); - assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &["one".to_string(), "two".to_string()] - )); - assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &["one".to_string()] - )); - assert!(!is_subset(&["one".to_string(), "two".to_string(), "three".to_string()], &[])); - } -} +pub mod constants; +pub mod consumer_config; +pub mod provider_config; +pub mod misc; diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs new file mode 100644 index 00000000..58c5577d --- /dev/null +++ b/samples/common/src/misc.rs @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +use log::{debug, info}; +use samples_protobuf_data_access::chariott::{ + common::v1::{ + discover_fulfillment, + DiscoverIntent, + fulfillment::Fulfillment as FulfillmentEnum, + intent::Intent as IntentEnum, + Intent as IntentMessage, + }, + runtime::v1::{FulfillRequest}, +}; +use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; +use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdRequest}; +use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; +use tonic::{Request, Status}; + +/// Is the provided subset a subset of the provided superset? +/// +/// # Arguments +/// `subset` - The provided subset. +/// `superset` - The provided superset. +pub fn is_subset(subset: &[String], superset: &[String]) -> bool { + subset.iter().all(|subset_member| { + superset.iter().any(|supserset_member| subset_member == supserset_member) + }) +} + +/// Find a provider endpoint that satifies the requirements. +/// +/// # Arguments +/// `invehcile_digitial_twin_servuce_uri` - iI-vehicle digital twin service URI. +/// `entity_id` - The matching entity id. +/// `protocol` - The required protocol. +/// `operations` - The required operations. +pub async fn find_provider_endpoint( + invehicle_digitial_twin_servuce_uri: &'static str, + entity_id: &str, + protocol: &str, + operations: &[String], +) -> Result { + info!("Sending a find_by_id request for entity id {entity_id} to the In-Vehicle Digital Twin Service URI {invehicle_digitial_twin_servuce_uri}"); + let mut client = DigitalTwinClient::connect(invehicle_digitial_twin_servuce_uri) + .await + .map_err(|error| format!("{error}"))?; + let request = tonic::Request::new(FindByIdRequest { id: entity_id.to_string() }); + let response = client.find_by_id(request).await.map_err(|error| error.to_string())?; + let response_inner = response.into_inner(); + debug!("Received the response for the find_by_id request"); + info!("response_payload: {:?}", response_inner.entity_access_info); + + let entity_access_info = response_inner.entity_access_info.expect("Did not find the entity"); + + let mut matching_endpoint_info_option: Option = None; + for endpoint_info in entity_access_info.endpoint_info_list { + // We require and endpoint that supports the protocol and supports all of the operations. + if endpoint_info.protocol == protocol + && is_subset(operations, endpoint_info.operations.as_slice()) + { + matching_endpoint_info_option = Some(endpoint_info); + break; + } + } + + if matching_endpoint_info_option.is_none() { + return Err("Did not find an endpoint that met our requirements".to_string()); + } + + let result = matching_endpoint_info_option.unwrap(); + + info!("Found a matching endpoint for entity id {entity_id} that has URI {}", result.uri); + + Ok(result) +} + +pub async fn discover_digital_twin_services_using_chariott(chariott_url: &str) -> Result, Status> { + + // let chariott_url = "http://0.0.0.0:4243"; + + let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; + + let request = Request::new(FulfillRequest { + namespace: "sdv.ibeji".to_string(), + intent: Some(IntentMessage { + intent: Some(IntentEnum::Discover(DiscoverIntent {})), + }), + }); + + // Get list of services at the requested namespace, if any. + let services: Option> = client + .fulfill(request) + .await? + .into_inner() + .fulfillment + .and_then(|fulfillment_message| fulfillment_message.fulfillment) + .and_then(|fulfillment_enum| match fulfillment_enum { + FulfillmentEnum::Discover(discover) => { + Some(discover.services.into_iter().collect()) + } + _ => None, + }); + + if services.is_some() { + for service in services.unwrap() { + if service.schema_kind == "grpc+proto" { + return Ok(Some(service.url.to_string())) + } + } + } + + Ok(None) +} + +#[cfg(test)] +mod ibeji_common_misc_tests { + use super::*; + + #[test] + fn is_subset_test() { + assert!(is_subset(&[], &[])); + assert!(is_subset(&[], &["one".to_string()])); + assert!(is_subset(&[], &["one".to_string(), "two".to_string()])); + assert!(is_subset(&["one".to_string()], &["one".to_string(), "two".to_string()])); + assert!(is_subset( + &["one".to_string(), "two".to_string()], + &["one".to_string(), "two".to_string()] + )); + assert!(!is_subset( + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string(), "two".to_string()] + )); + assert!(!is_subset( + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string()] + )); + assert!(!is_subset(&["one".to_string(), "two".to_string(), "three".to_string()], &[])); + } +} diff --git a/samples/common/src/provider_config.rs b/samples/common/src/provider_config.rs new file mode 100644 index 00000000..389dbdea --- /dev/null +++ b/samples/common/src/provider_config.rs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +#![cfg(feature = "yaml")] + +use serde_derive::Deserialize; +use config::{Config, File, FileFormat}; + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub provider_authority: String, + pub chariott_url: Option, + pub invehicle_digital_twin_url: Option, +} + +pub fn load_settings() -> Settings { + let config = Config::builder() + .add_source(File::new("provider_settings", FileFormat::Yaml)) + .build() + .unwrap(); + + let settings: Settings = config.try_deserialize().unwrap(); + + settings +} diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index cefc42d3..d004c477 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -7,7 +7,8 @@ mod consumer_impl; use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::find_provider_endpoint; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::{ diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 2dbe29a2..2d83c8b1 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -9,7 +9,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use samples_common::{digital_twin_operation, digital_twin_protocol}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; diff --git a/samples/property/Cargo.toml b/samples/property/Cargo.toml index ea21637e..c512a56d 100644 --- a/samples/property/Cargo.toml +++ b/samples/property/Cargo.toml @@ -20,6 +20,7 @@ samples-protobuf-data-access = { path = "../protobuf_data_access" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } +url = { workspace = true } uuid = { workspace = true, features = ["v4", "fast-rng", "macro-diagnostics"] } [build-dependencies] @@ -31,4 +32,4 @@ path = "provider/src/main.rs" [[bin]] name = "property-consumer" -path = "consumer/src/main.rs" \ No newline at end of file +path = "consumer/src/main.rs" diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index b1072fd7..97c398f5 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -5,18 +5,19 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use samples_common::{digital_twin_operation, digital_twin_protocol, discover_digital_twin_services_using_chariott, find_provider_endpoint}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::{discover_digital_twin_services_using_chariott, find_provider_endpoint}; +use samples_common::consumer_config::load_settings; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::SubscribeRequest; use std::net::SocketAddr; use tonic::transport::Server; +// use url::{Url, ParseError}; mod consumer_impl; -// const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 - -const CONSUMER_AUTHORITY: &str = "0.0.0.0:6010"; +// const CONSUMER_AUTHORITY: &str = "0.0.0.0:6010"; #[tokio::main] async fn main() -> Result<(), Box> { @@ -25,22 +26,49 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); + let settings = load_settings(); + let consumer_authority = settings.consumer_authority; + + // let invehicle_digital_twin_url = "dummy".to_string(); + + // if load_settings.invehicle_digital_twin_url.is_none() && load_settings.chariott_url.is_none() { + let invehicle_digital_twin_url = match settings.invehicle_digital_twin_url { + Some(value) => value, + None => { + match settings.chariott_url { + // Some(value) => value, + Some(value) => { + match discover_digital_twin_services_using_chariott(&value).await { + Ok(Some(value)) => value, + Ok(None) => Err("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")?, + Err(error) => Err(format!("Failed to discover the in-vehicle digital twin service's URL due to error: {error}"))? + } + } + None => { + Err("The settings file must set a chariott_url setting when the invehicle_digital_twin_url is not set.")? + } + } + } + }; + // Setup the HTTP server. - let addr: SocketAddr = CONSUMER_AUTHORITY.parse()?; + let addr: SocketAddr = consumer_authority.parse().unwrap(); let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); - info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{consumer_authority}'"); - let url_option = discover_digital_twin_services_using_chariott().await?; +/* + let url_option = discover_digital_twin_services_using_chariott().await?,ok_or(); if url_option.is_none() { return Err("Failed to discover the in-vehicle digital twin service's URL")?; } let url = url_option.unwrap().clone(); - +*/ + // Workarounhd: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str - let static_url_str = Box::leak(url.into_boxed_str()); + let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); let provider_endpoint_info = find_provider_endpoint( static_url_str, @@ -55,7 +83,7 @@ async fn main() -> Result<(), Box> { info!("The URI for the AmbientAirTemperature property's provider is {provider_uri}"); - let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 + let consumer_uri = format!("http://{consumer_authority}"); // Devskim: ignore DS137138 // Subscribing to the ambient air temperature data feed. info!( diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index b9a1fd62..b0f80c59 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use samples_common::{digital_twin_operation, digital_twin_protocol}; +use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; From f6b56b5c2132800ab9e1b2be5453b6e3943ea431 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:02:50 -0700 Subject: [PATCH 04/23] Use Chariott --- core/invehicle-digital-twin/src/main.rs | 25 ++-- .../src/providerservice_impl.rs | 119 +++--------------- samples/command/consumer/src/main.rs | 8 +- samples/common/src/misc.rs | 29 +++-- samples/mixed/consumer/src/main.rs | 20 +-- samples/property/consumer/src/main.rs | 24 +--- 6 files changed, 70 insertions(+), 155 deletions(-) diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 152e4a8e..096df9c4 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -16,29 +16,32 @@ use tonic::{Request, Status}; use tonic::transport::Server; use url::Url; -// use crate::invehicle_digital_twin_config::load_settings; - mod digitaltwin_impl; mod invehicle_digital_twin_config; mod providerservice_impl; -// const INVEHICLE_DIGITAL_TWIN_AUTHORITY: &str = "0.0.0.0:5010"; - -pub async fn register_ibeji_services_with_chariott(chariott_url: &str, invehicle_digital_twin_url: &str) -> Result<(), Status> { - // let chariott_url = "http://0.0.0.0:4243"; +pub const DIGITAL_TWIN_SERVICE_NAME: &str = "digital_twin"; +pub const DIGITAL_TWIN_SERVICE_VERSION: &str = "1.0"; +pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; +/// Register the digital twin service with Chariott. +/// +/// # Arguments +/// * `chariott_url` - Chariott's URL. +/// * `invehicle_digital_twin_url` - In-vehcile Digital Twin Service's URL. +pub async fn register_digital_twin_service_with_chariott(chariott_url: &str, invehicle_digital_twin_url: &str) -> Result<(), Status> { let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; let service = Some(IntentServiceRegistration { - name: "digital-twin".to_string(), - version: "1.0".to_string(), + name: DIGITAL_TWIN_SERVICE_NAME.to_string(), + version: DIGITAL_TWIN_SERVICE_VERSION.to_string(), url: invehicle_digital_twin_url.to_string(), locality: intent_service_registration::ExecutionLocality::Local as i32, }); let intents = vec![ IntentRegistration { - namespace: "sdv.ibeji".to_string(), + namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), intent: intent_registration::Intent::Discover as i32, }, ]; @@ -66,6 +69,7 @@ async fn main() -> Result<(), Box> { info!("The In-Vehicle Digital Twin Service has started."); + // Load the config. let settings = invehicle_digital_twin_config::load_settings(); let invehicle_digital_twin_authority = settings.invehicle_digital_twin_authority; let chariott_url_option = settings.chariott_url; @@ -85,8 +89,9 @@ async fn main() -> Result<(), Box> { .serve(addr); info!("The HTTP server is listening on address '{invehicle_digital_twin_address}'"); + // Register the digital twin service with Chariott if Chariott's URL was provided in the config. if chariott_url_option.is_some() { - register_ibeji_services_with_chariott(&chariott_url_option.unwrap(), &invehicle_digital_twin_address).await?; + register_digital_twin_service_with_chariott(&chariott_url_option.unwrap(), &invehicle_digital_twin_address).await?; } server_future.await?; diff --git a/core/invehicle-digital-twin/src/providerservice_impl.rs b/core/invehicle-digital-twin/src/providerservice_impl.rs index fa77dc84..b246fd93 100644 --- a/core/invehicle-digital-twin/src/providerservice_impl.rs +++ b/core/invehicle-digital-twin/src/providerservice_impl.rs @@ -2,17 +2,6 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -// extern crate iref; - -// use core_protobuf_data_access::chariott::common::v1::Fulfillment; -/* -use core_protobuf_data_access::chariott::provider::v1::provider_service_server::ProviderService; -use core_protobuf_data_access::chariott::provider::v1::{ - FulfillRequest, FulfillResponse, -}; -use log::info; -*/ - use core_protobuf_data_access::chariott::{ common::v1::{ discover_fulfillment::Service, DiscoverFulfillment, fulfillment::Fulfillment as FulfillmentEnum, @@ -25,6 +14,9 @@ use std::collections::HashMap; use tonic::{Request, Response, Status}; use url::Url; +pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; +pub const CHARIOTT_SCHEMA_REFERENCE_FOR_DIGITAL_TWIN_SERVICE : &str = "digital_twin.v1"; + #[derive(Debug)] pub struct ProviderServiceImpl { pub url: Url, @@ -50,8 +42,8 @@ impl ProviderService for ProviderServiceImpl { IntentEnum::Discover(_intent) => Ok(FulfillmentEnum::Discover(DiscoverFulfillment { services: vec![Service { url: self.url.to_string(), - schema_kind: "grpc+proto".to_owned(), - schema_reference: "example.provider.v1".to_owned(), + schema_kind: CHARIOTT_SCHEMA_KIND_FOR_GRPC.to_owned(), + schema_reference: CHARIOTT_SCHEMA_REFERENCE_FOR_DIGITAL_TWIN_SERVICE.to_owned(), metadata: HashMap::new(), }], })), @@ -75,96 +67,25 @@ impl ProviderServiceImpl { #[cfg(test)] mod providerservice_impl_tests { use super::*; - // use core_protobuf_data_access::digital_twin::v1::EndpointInfo; + use core_protobuf_data_access::chariott::common::v1::{ + DiscoverIntent, Intent as IntentMessage + }; -/* #[tokio::test] - async fn find_by_id_test() { - let operations = vec![String::from("Subscribe"), String::from("Unsubscribe")]; - - let endpoint_info = EndpointInfo { - protocol: String::from("grpc"), - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), - operations, - }; + async fn fulfill_test() { + let provider_service_impl = + ProviderServiceImpl { url: Url::parse("http://0.0.0.0:80").unwrap() }; + + let request = Request::new(FulfillRequest { + intent: Some(IntentMessage { + intent: Some(IntentEnum::Discover(DiscoverIntent {})), + }), + }); + let result = provider_service_impl.fulfill(request).await; + assert!(result.is_ok(), "fulfill result is not okay: {result:?}"); - let entity_access_info = EntityAccessInfo { - name: String::from("AmbientAirTemperature"), - id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), - description: String::from("Ambient air temperature"), - endpoint_info_list: vec![endpoint_info], - }; - - let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); - - let digital_twin_impl = - DigitalTwinImpl { entity_access_info_map: entity_access_info_map.clone() }; - - // This block controls the lifetime of the lock. - { - let mut lock: RwLockWriteGuard> = - entity_access_info_map.write(); - lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); - } - - let request = tonic::Request::new(FindByIdRequest { - id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), - }); - let result = digital_twin_impl.find_by_id(request).await; - assert!(result.is_ok()); let response = result.unwrap(); let response_inner = response.into_inner(); - - assert!(response_inner.entity_access_info.is_some()); - - let response_entity_access_info = response_inner.entity_access_info.unwrap(); - - assert_eq!( - response_entity_access_info.id, - "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" - ); - assert_eq!(response_entity_access_info.endpoint_info_list.len(), 1); - assert_eq!( - response_entity_access_info.endpoint_info_list[0].uri, - "http://[::1]:40010" // Devskim: ignore DS137138 - ); - } - - #[tokio::test] - async fn register_test() { - let endpoint_info = EndpointInfo { - protocol: String::from("grpc"), - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), - operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], - }; - - let entity_access_info = EntityAccessInfo { - name: String::from("AmbientAirTemperature"), - id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), - description: String::from("Ambient air temperature"), - endpoint_info_list: vec![endpoint_info], - }; - - let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); - - let digital_twin_impl = - DigitalTwinImpl { entity_access_info_map: entity_access_info_map.clone() }; - - let request = tonic::Request::new(RegisterRequest { - entity_access_info_list: vec![entity_access_info], - }); - let result = digital_twin_impl.register(request).await; - assert!(result.is_ok(), "register result is not okay: {result:?}"); - - // This block controls the lifetime of the lock. - { - let lock: RwLockReadGuard> = - entity_access_info_map.read(); - // Make sure that we populated the entity map from the contents of the DTDL. - assert_eq!(lock.len(), 1, "expected length was 1, actual length is {}", lock.len()); - } + assert!(response_inner.fulfillment.is_some()); } -*/ } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 0c60488a..dba3c1c3 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::find_provider_endpoint; +use samples_common::misc::discover_digital_twin_provider_using_ibeji; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::InvokeRequest; @@ -17,7 +17,7 @@ use tokio::time::{sleep, Duration}; use tonic::transport::Server; use uuid::Uuid; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 +const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 const CONSUMER_AUTHORITY: &str = "[::1]:60010"; /// Start the show notification repeater. @@ -79,8 +79,8 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); - let provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index 58c5577d..5f54b2aa 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -18,6 +18,9 @@ use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdReque use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; use tonic::{Request, Status}; +pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; +pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; + /// Is the provided subset a subset of the provided superset? /// /// # Arguments @@ -29,21 +32,21 @@ pub fn is_subset(subset: &[String], superset: &[String]) -> bool { }) } -/// Find a provider endpoint that satifies the requirements. +/// Use Ibeji to discover the endpoint for a digital twin provider that satifies the requirements. /// /// # Arguments -/// `invehcile_digitial_twin_servuce_uri` - iI-vehicle digital twin service URI. +/// `invehcile_digitial_twin_servuce_url` - In-vehicle digital twin service URL. /// `entity_id` - The matching entity id. /// `protocol` - The required protocol. /// `operations` - The required operations. -pub async fn find_provider_endpoint( - invehicle_digitial_twin_servuce_uri: &'static str, +pub async fn discover_digital_twin_provider_using_ibeji( + invehicle_digitial_twin_servuce_url: &'static str, entity_id: &str, protocol: &str, operations: &[String], ) -> Result { - info!("Sending a find_by_id request for entity id {entity_id} to the In-Vehicle Digital Twin Service URI {invehicle_digitial_twin_servuce_uri}"); - let mut client = DigitalTwinClient::connect(invehicle_digitial_twin_servuce_uri) + info!("Sending a find_by_id request for entity id {entity_id} to the In-Vehicle Digital Twin Service URL {invehicle_digitial_twin_servuce_url}"); + let mut client = DigitalTwinClient::connect(invehicle_digitial_twin_servuce_url) .await .map_err(|error| format!("{error}"))?; let request = tonic::Request::new(FindByIdRequest { id: entity_id.to_string() }); @@ -76,14 +79,15 @@ pub async fn find_provider_endpoint( Ok(result) } -pub async fn discover_digital_twin_services_using_chariott(chariott_url: &str) -> Result, Status> { - - // let chariott_url = "http://0.0.0.0:4243"; - +/// Use Chariott to discover the endpoint for the digital twin service. +/// +/// # Arguments +/// * `chariott_url` - Chariott's URL. +pub async fn discover_digital_twin_service_using_chariott(chariott_url: &str) -> Result, Status> { let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; let request = Request::new(FulfillRequest { - namespace: "sdv.ibeji".to_string(), + namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), intent: Some(IntentMessage { intent: Some(IntentEnum::Discover(DiscoverIntent {})), }), @@ -103,9 +107,10 @@ pub async fn discover_digital_twin_services_using_chariott(chariott_url: &str) - _ => None, }); + // If we discovered one or more service, then return the URL for the first one that uses gRPC. if services.is_some() { for service in services.unwrap() { - if service.schema_kind == "grpc+proto" { + if service.schema_kind == CHARIOTT_SCHEMA_KIND_FOR_GRPC { return Ok(Some(service.url.to_string())) } } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index d004c477..aa4aad09 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::find_provider_endpoint; +use samples_common::misc::discover_digital_twin_provider_using_ibeji; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::{ @@ -19,7 +19,7 @@ use tokio::time::{sleep, Duration}; use tonic::transport::Server; use uuid::Uuid; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 +const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 const CONSUMER_AUTHORITY: &str = "[::1]:60010"; @@ -144,8 +144,8 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); - let show_notification_command_provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + let show_notification_command_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], @@ -155,8 +155,8 @@ async fn main() -> Result<(), Box> { let show_notification_command_provider_uri = show_notification_command_provider_endpoint_info.uri; - let ambient_air_temperature_property_provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + let ambient_air_temperature_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], @@ -166,8 +166,8 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_property_provider_uri = ambient_air_temperature_property_provider_endpoint_info.uri; - let is_air_conditioning_active_property_provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + let is_air_conditioning_active_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::SET.to_string()], @@ -177,8 +177,8 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_provider_uri = is_air_conditioning_active_property_provider_endpoint_info.uri; - let hybrid_battery_remaining_property_provider_endpoint_info = find_provider_endpoint( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, + let hybrid_battery_remaining_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, sdv::vehicle::obd::hybrid_battery_remaining::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 97c398f5..89409375 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -6,19 +6,16 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{discover_digital_twin_services_using_chariott, find_provider_endpoint}; +use samples_common::misc::{discover_digital_twin_service_using_chariott, discover_digital_twin_provider_using_ibeji}; use samples_common::consumer_config::load_settings; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::SubscribeRequest; use std::net::SocketAddr; use tonic::transport::Server; -// use url::{Url, ParseError}; mod consumer_impl; -// const CONSUMER_AUTHORITY: &str = "0.0.0.0:6010"; - #[tokio::main] async fn main() -> Result<(), Box> { // Setup logging. @@ -27,18 +24,13 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); let settings = load_settings(); - let consumer_authority = settings.consumer_authority; - - // let invehicle_digital_twin_url = "dummy".to_string(); - // if load_settings.invehicle_digital_twin_url.is_none() && load_settings.chariott_url.is_none() { let invehicle_digital_twin_url = match settings.invehicle_digital_twin_url { Some(value) => value, None => { match settings.chariott_url { - // Some(value) => value, Some(value) => { - match discover_digital_twin_services_using_chariott(&value).await { + match discover_digital_twin_service_using_chariott(&value).await { Ok(Some(value)) => value, Ok(None) => Err("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")?, Err(error) => Err(format!("Failed to discover the in-vehicle digital twin service's URL due to error: {error}"))? @@ -52,25 +44,17 @@ async fn main() -> Result<(), Box> { }; // Setup the HTTP server. + let consumer_authority = settings.consumer_authority; let addr: SocketAddr = consumer_authority.parse().unwrap(); let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{consumer_authority}'"); -/* - let url_option = discover_digital_twin_services_using_chariott().await?,ok_or(); - if url_option.is_none() { - return Err("Failed to discover the in-vehicle digital twin service's URL")?; - } - - let url = url_option.unwrap().clone(); -*/ - // Workarounhd: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); - let provider_endpoint_info = find_provider_endpoint( + let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( static_url_str, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, From af9b225530535f0a948e41e56766dc787b611a19 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:21:44 -0700 Subject: [PATCH 05/23] Use Chariott --- Cargo.toml | 9 +- .../src/invehicle_digital_twin_config.rs | 2 +- core/invehicle-digital-twin/src/main.rs | 55 ++++---- .../src/providerservice_impl.rs | 16 ++- core/protobuf_data_access/build.rs | 18 ++- core/protobuf_data_access/src/lib.rs | 1 - samples/common/Cargo.toml | 2 + samples/common/src/consumer_config.rs | 2 +- samples/common/src/lib.rs | 4 +- samples/common/src/misc.rs | 117 ++++++++++++++---- samples/common/src/provider_config.rs | 2 +- samples/mixed/consumer/src/main.rs | 71 ++++++----- samples/property/consumer/src/main.rs | 65 +++++----- samples/protobuf_data_access/build.rs | 18 ++- 14 files changed, 235 insertions(+), 147 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e74a759c..aa782ad6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ members = [ async-std = "^1.5" config = "0.13.3" env_logger= "0.10.0" +fixed = "1.23.1" futures = "0.3" generic-json = "^0.7" iref = "^2.0.3" @@ -35,15 +36,15 @@ log = "^0.4" parking_lot = "0.12.1" prost = "0.11" prost-types = "0.11" -regex = " 1.8.2" -tokio = "1.0" -tonic = "0.9.2" -tonic-build = "0.9.2" +regex = " 1.8.3" serde = "1.0.160" serde_derive = "1.0.163" serde_json = "^1.0" strum = "0.24" strum_macros = "0.24" +tokio = "1.0" +tonic = "0.9.2" +tonic-build = "0.9.2" url = "2.3.1" uuid = "1.2.2" yaml-rust = "0.4" diff --git a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs index 96e42b2c..b53b2a66 100644 --- a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs +++ b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs @@ -4,8 +4,8 @@ #![cfg(feature = "yaml")] -use serde_derive::Deserialize; use config::{Config, File, FileFormat}; +use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct Settings { diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 096df9c4..4e6f7d6a 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -2,18 +2,21 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -use core_protobuf_data_access::digital_twin::v1::digital_twin_server::DigitalTwinServer; use core_protobuf_data_access::chariott::provider::v1::provider_service_server::ProviderServiceServer; use core_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; -use core_protobuf_data_access::chariott::runtime::v1::{intent_registration, IntentRegistration, intent_service_registration, IntentServiceRegistration, RegisterRequest}; +use core_protobuf_data_access::chariott::runtime::v1::{ + intent_registration, intent_service_registration, IntentRegistration, + IntentServiceRegistration, RegisterRequest, +}; +use core_protobuf_data_access::digital_twin::v1::digital_twin_server::DigitalTwinServer; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::RwLock; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; -use tonic::{Request, Status}; use tonic::transport::Server; +use tonic::{Request, Status}; use url::Url; mod digitaltwin_impl; @@ -29,8 +32,13 @@ pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; /// # Arguments /// * `chariott_url` - Chariott's URL. /// * `invehicle_digital_twin_url` - In-vehcile Digital Twin Service's URL. -pub async fn register_digital_twin_service_with_chariott(chariott_url: &str, invehicle_digital_twin_url: &str) -> Result<(), Status> { - let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; +pub async fn register_digital_twin_service_with_chariott( + chariott_url: &str, + invehicle_digital_twin_url: &str, +) -> Result<(), Status> { + let mut client = ChariottServiceClient::connect(chariott_url.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; let service = Some(IntentServiceRegistration { name: DIGITAL_TWIN_SERVICE_NAME.to_string(), @@ -39,17 +47,12 @@ pub async fn register_digital_twin_service_with_chariott(chariott_url: &str, inv locality: intent_service_registration::ExecutionLocality::Local as i32, }); - let intents = vec![ - IntentRegistration { - namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), - intent: intent_registration::Intent::Discover as i32, - }, - ]; + let intents = vec![IntentRegistration { + namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), + intent: intent_registration::Intent::Discover as i32, + }]; - let request = Request::new(RegisterRequest { - service, - intents, - }); + let request = Request::new(RegisterRequest { service, intents }); let response = client.register(request).await; @@ -59,7 +62,7 @@ pub async fn register_digital_twin_service_with_chariott(chariott_url: &str, inv info!("{:?}", response.unwrap().into_inner()); - return Ok(()) + return Ok(()); } #[tokio::main] @@ -79,19 +82,23 @@ async fn main() -> Result<(), Box> { let digitaltwin_impl = digitaltwin_impl::DigitalTwinImpl { entity_access_info_map: Arc::new(RwLock::new(HashMap::new())), }; - let invehicle_digital_twin_address = format!("http://{invehicle_digital_twin_authority}"); // Devskim: ignore DS137138 + let invehicle_digital_twin_address = format!("http://{invehicle_digital_twin_authority}"); // Devskim: ignore DS137138 let invehicle_digital_twin_url = Url::parse(&invehicle_digital_twin_address)?; - let providerservice_impl = providerservice_impl::ProviderServiceImpl::new(invehicle_digital_twin_url); - let server_future = - Server::builder() - .add_service(DigitalTwinServer::new(digitaltwin_impl)) - .add_service(ProviderServiceServer::new(providerservice_impl)) - .serve(addr); + let providerservice_impl = + providerservice_impl::ProviderServiceImpl::new(invehicle_digital_twin_url); + let server_future = Server::builder() + .add_service(DigitalTwinServer::new(digitaltwin_impl)) + .add_service(ProviderServiceServer::new(providerservice_impl)) + .serve(addr); info!("The HTTP server is listening on address '{invehicle_digital_twin_address}'"); // Register the digital twin service with Chariott if Chariott's URL was provided in the config. if chariott_url_option.is_some() { - register_digital_twin_service_with_chariott(&chariott_url_option.unwrap(), &invehicle_digital_twin_address).await?; + register_digital_twin_service_with_chariott( + &chariott_url_option.unwrap(), + &invehicle_digital_twin_address, + ) + .await?; } server_future.await?; diff --git a/core/invehicle-digital-twin/src/providerservice_impl.rs b/core/invehicle-digital-twin/src/providerservice_impl.rs index b246fd93..ee053443 100644 --- a/core/invehicle-digital-twin/src/providerservice_impl.rs +++ b/core/invehicle-digital-twin/src/providerservice_impl.rs @@ -4,8 +4,8 @@ use core_protobuf_data_access::chariott::{ common::v1::{ - discover_fulfillment::Service, DiscoverFulfillment, fulfillment::Fulfillment as FulfillmentEnum, - Fulfillment as FulfillmentMessage, intent::Intent as IntentEnum, + discover_fulfillment::Service, fulfillment::Fulfillment as FulfillmentEnum, + intent::Intent as IntentEnum, DiscoverFulfillment, Fulfillment as FulfillmentMessage, }, provider::v1::{provider_service_server::ProviderService, FulfillRequest, FulfillResponse}, }; @@ -15,7 +15,7 @@ use tonic::{Request, Response, Status}; use url::Url; pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; -pub const CHARIOTT_SCHEMA_REFERENCE_FOR_DIGITAL_TWIN_SERVICE : &str = "digital_twin.v1"; +pub const CHARIOTT_SCHEMA_REFERENCE_FOR_DIGITAL_TWIN_SERVICE: &str = "digital_twin.v1"; #[derive(Debug)] pub struct ProviderServiceImpl { @@ -55,7 +55,7 @@ impl ProviderService for ProviderServiceImpl { fulfillment: Some(FulfillmentMessage { fulfillment: Some(f) }), }) }) - } + } } impl ProviderServiceImpl { @@ -68,7 +68,7 @@ impl ProviderServiceImpl { mod providerservice_impl_tests { use super::*; use core_protobuf_data_access::chariott::common::v1::{ - DiscoverIntent, Intent as IntentMessage + DiscoverIntent, Intent as IntentMessage, }; #[tokio::test] @@ -77,10 +77,8 @@ mod providerservice_impl_tests { ProviderServiceImpl { url: Url::parse("http://0.0.0.0:80").unwrap() }; let request = Request::new(FulfillRequest { - intent: Some(IntentMessage { - intent: Some(IntentEnum::Discover(DiscoverIntent {})), - }), - }); + intent: Some(IntentMessage { intent: Some(IntentEnum::Discover(DiscoverIntent {})) }), + }); let result = provider_service_impl.fulfill(request).await; assert!(result.is_ok(), "fulfill result is not okay: {result:?}"); diff --git a/core/protobuf_data_access/build.rs b/core/protobuf_data_access/build.rs index 2255067b..a0ed6684 100644 --- a/core/protobuf_data_access/build.rs +++ b/core/protobuf_data_access/build.rs @@ -10,16 +10,14 @@ fn main() -> Result<(), Box> { &["../../interfaces/digital_twin/v1/digital_twin.proto"], &["../../interfaces/digital_twin/v1/"], )?; - tonic_build::configure() - .compile( - &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], - &["../../external/chariott/proto"], - )?; - tonic_build::configure() - .compile( - &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], - &["../../external/chariott/proto"], - )?; + tonic_build::configure().compile( + &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], + &["../../external/chariott/proto"], + )?; + tonic_build::configure().compile( + &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], + &["../../external/chariott/proto"], + )?; Ok(()) } diff --git a/core/protobuf_data_access/src/lib.rs b/core/protobuf_data_access/src/lib.rs index fa204526..70c53a91 100644 --- a/core/protobuf_data_access/src/lib.rs +++ b/core/protobuf_data_access/src/lib.rs @@ -25,4 +25,3 @@ pub mod chariott { } } } - diff --git a/samples/common/Cargo.toml b/samples/common/Cargo.toml index 8a272d2a..275edaa2 100644 --- a/samples/common/Cargo.toml +++ b/samples/common/Cargo.toml @@ -10,10 +10,12 @@ license = "MIT" [dependencies] config = { workspace = true } +fixed = { workspace = true } log = { workspace = true } samples-protobuf-data-access = { path = "../protobuf_data_access" } serde = { workspace = true, features = ["derive"] } serde_derive = { workspace = true } +tokio = { workspace = true } tonic = { workspace = true } yaml-rust = { workspace = true, optional = true } diff --git a/samples/common/src/consumer_config.rs b/samples/common/src/consumer_config.rs index d1a18985..bc73068f 100644 --- a/samples/common/src/consumer_config.rs +++ b/samples/common/src/consumer_config.rs @@ -4,8 +4,8 @@ #![cfg(feature = "yaml")] -use serde_derive::Deserialize; use config::{Config, File, FileFormat}; +use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct Settings { diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index fffb294d..225026c9 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -2,7 +2,9 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +#![feature(async_closure)] + pub mod constants; pub mod consumer_config; -pub mod provider_config; pub mod misc; +pub mod provider_config; diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index 5f54b2aa..774e1c1e 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -3,20 +3,20 @@ // SPDX-License-Identifier: MIT use log::{debug, info}; +use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; use samples_protobuf_data_access::chariott::{ common::v1::{ - discover_fulfillment, - DiscoverIntent, - fulfillment::Fulfillment as FulfillmentEnum, - intent::Intent as IntentEnum, - Intent as IntentMessage, + discover_fulfillment, fulfillment::Fulfillment as FulfillmentEnum, + intent::Intent as IntentEnum, DiscoverIntent, Intent as IntentMessage, }, - runtime::v1::{FulfillRequest}, + runtime::v1::FulfillRequest, }; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdRequest}; -use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; -use tonic::{Request, Status}; +use std::future::Future; +use tonic::{Code, Request, Status}; + +use tokio::time::{sleep, Duration}; pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; @@ -24,23 +24,64 @@ pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; /// Is the provided subset a subset of the provided superset? /// /// # Arguments -/// `subset` - The provided subset. -/// `superset` - The provided superset. +/// * `subset` - The provided subset. +/// * `superset` - The provided superset. pub fn is_subset(subset: &[String], superset: &[String]) -> bool { subset.iter().all(|subset_member| { superset.iter().any(|supserset_member| subset_member == supserset_member) }) } +/// +/// Retry an async function that uses tonic::Status in for its error result. +/// +/// # Arguments +/// * `max_retries` - The maximu number of retries. +/// * `duration_between_attempts` - The duration of time attempts. +/// * `function` - THe function. +pub async fn retry_async_based_on_status Fut>( + max_retries: i32, + duration_between_attempts: Duration, + mut function: F, +) -> Result +where + Fut: Future>, +{ + let mut last_status; + let mut retries: i32 = 0; + + loop { + match function().await { + Ok(t) => return Ok(t), + Err(status) => { + if status.code() == Code::Unavailable || status.code() == Code::Internal { + last_status = status; + } else { + return Err(status); + } + } + } + if retries < max_retries { + debug!("Retrying a call."); + sleep(duration_between_attempts).await; + retries += 1; + } else { + break; + } + } + + Err(last_status) +} + /// Use Ibeji to discover the endpoint for a digital twin provider that satifies the requirements. /// /// # Arguments -/// `invehcile_digitial_twin_servuce_url` - In-vehicle digital twin service URL. -/// `entity_id` - The matching entity id. -/// `protocol` - The required protocol. -/// `operations` - The required operations. +/// * `invehcile_digitial_twin_servuce_url` - In-vehicle digital twin service URL. +/// * `entity_id` - The matching entity id. +/// * `protocol` - The required protocol. +/// * `operations` - The required operations. pub async fn discover_digital_twin_provider_using_ibeji( - invehicle_digitial_twin_servuce_url: &'static str, + invehicle_digitial_twin_servuce_url: &'static str, entity_id: &str, protocol: &str, operations: &[String], @@ -83,14 +124,16 @@ pub async fn discover_digital_twin_provider_using_ibeji( /// /// # Arguments /// * `chariott_url` - Chariott's URL. -pub async fn discover_digital_twin_service_using_chariott(chariott_url: &str) -> Result, Status> { - let mut client = ChariottServiceClient::connect(chariott_url.to_string()).await.map_err(|e|Status::internal(e.to_string()))?; +pub async fn discover_digital_twin_service_using_chariott( + chariott_url: &str, +) -> Result, Status> { + let mut client = ChariottServiceClient::connect(chariott_url.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; let request = Request::new(FulfillRequest { namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), - intent: Some(IntentMessage { - intent: Some(IntentEnum::Discover(DiscoverIntent {})), - }), + intent: Some(IntentMessage { intent: Some(IntentEnum::Discover(DiscoverIntent {})) }), }); // Get list of services at the requested namespace, if any. @@ -101,9 +144,7 @@ pub async fn discover_digital_twin_service_using_chariott(chariott_url: &str) -> .fulfillment .and_then(|fulfillment_message| fulfillment_message.fulfillment) .and_then(|fulfillment_enum| match fulfillment_enum { - FulfillmentEnum::Discover(discover) => { - Some(discover.services.into_iter().collect()) - } + FulfillmentEnum::Discover(discover) => Some(discover.services.into_iter().collect()), _ => None, }); @@ -111,7 +152,7 @@ pub async fn discover_digital_twin_service_using_chariott(chariott_url: &str) -> if services.is_some() { for service in services.unwrap() { if service.schema_kind == CHARIOTT_SCHEMA_KIND_FOR_GRPC { - return Ok(Some(service.url.to_string())) + return Ok(Some(service.url.to_string())); } } } @@ -119,6 +160,34 @@ pub async fn discover_digital_twin_service_using_chariott(chariott_url: &str) -> Ok(None) } +pub async fn retrieve_invehicle_digital_twin_url( + invehicle_digital_twin_url: Option, + chariott_url: Option, +) -> Result { + // Get the URL for the In-Vehicle Digital Twin Service. + // First try to use the one specified in the invehicle_digital_twin_url setting. + // If it is not set, then go to Chariott to obtain it. + let result = match invehicle_digital_twin_url { + Some(value) => value, + None => { + match chariott_url { + Some(value) => { + match retry_async_based_on_status(30, Duration::from_secs(1), || discover_digital_twin_service_using_chariott(&value)).await { + Ok(Some(value)) => value, + Ok(None) => Err("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")?, + Err(error) => Err(format!("Failed to discover the in-vehicle digital twin service's URL due to error: {error}"))? + } + } + None => { + Err("The settings file must set a chariott_url setting when the invehicle_digital_twin_url is not set.")? + } + } + } + }; + + Ok(result) +} + #[cfg(test)] mod ibeji_common_misc_tests { use super::*; diff --git a/samples/common/src/provider_config.rs b/samples/common/src/provider_config.rs index 389dbdea..816b9906 100644 --- a/samples/common/src/provider_config.rs +++ b/samples/common/src/provider_config.rs @@ -4,8 +4,8 @@ #![cfg(feature = "yaml")] -use serde_derive::Deserialize; use config::{Config, File, FileFormat}; +use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct Settings { diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index aa4aad09..17b64249 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -144,47 +144,54 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); - let show_notification_command_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, - sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, - digital_twin_protocol::GRPC, - &[digital_twin_operation::INVOKE.to_string()], - ) - .await - .unwrap(); + let show_notification_command_provider_endpoint_info = + discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, + digital_twin_protocol::GRPC, + &[digital_twin_operation::INVOKE.to_string()], + ) + .await + .unwrap(); let show_notification_command_provider_uri = show_notification_command_provider_endpoint_info.uri; - let ambient_air_temperature_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, - sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, - digital_twin_protocol::GRPC, - &[digital_twin_operation::SUBSCRIBE.to_string()], - ) - .await - .unwrap(); + let ambient_air_temperature_property_provider_endpoint_info = + discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, + digital_twin_protocol::GRPC, + &[digital_twin_operation::SUBSCRIBE.to_string()], + ) + .await + .unwrap(); let ambient_air_temperature_property_provider_uri = ambient_air_temperature_property_provider_endpoint_info.uri; - let is_air_conditioning_active_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, - sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, - digital_twin_protocol::GRPC, - &[digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::SET.to_string()], - ) - .await - .unwrap(); + let is_air_conditioning_active_property_provider_endpoint_info = + discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, + digital_twin_protocol::GRPC, + &[ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::SET.to_string(), + ], + ) + .await + .unwrap(); let is_air_conditioning_active_property_provider_uri = is_air_conditioning_active_property_provider_endpoint_info.uri; - let hybrid_battery_remaining_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, - sdv::vehicle::obd::hybrid_battery_remaining::ID, - digital_twin_protocol::GRPC, - &[digital_twin_operation::SUBSCRIBE.to_string()], - ) - .await - .unwrap(); + let hybrid_battery_remaining_property_provider_endpoint_info = + discover_digital_twin_provider_using_ibeji( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + sdv::vehicle::obd::hybrid_battery_remaining::ID, + digital_twin_protocol::GRPC, + &[digital_twin_operation::SUBSCRIBE.to_string()], + ) + .await + .unwrap(); let hybrid_battery_remaining_property_provider_uri = hybrid_battery_remaining_property_provider_endpoint_info.uri; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 89409375..390da13f 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -6,16 +6,38 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{discover_digital_twin_service_using_chariott, discover_digital_twin_provider_using_ibeji}; +use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::consumer_config::load_settings; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::SubscribeRequest; use std::net::SocketAddr; -use tonic::transport::Server; +use tokio::time::Duration; +use tonic::{Status, transport::Server}; mod consumer_impl; +/// Subscribe to the ambient air temperature. +/// +/// # Arguments +/// * `provider_uri` - The provider's URI. +/// * `consumer_uri` - The consumer's URI. +async fn subscribe_to_ambient_air_temperature( + provider_uri: &str, + consumer_uri: &str, +) -> Result<(), Status> { + let mut client = DigitalTwinProviderClient::connect(provider_uri.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; + let request = tonic::Request::new(SubscribeRequest { + entity_id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + consumer_uri: consumer_uri.to_string(), + }); + let _response = client.subscribe(request).await?; + + Ok(()) +} + #[tokio::main] async fn main() -> Result<(), Box> { // Setup logging. @@ -25,23 +47,11 @@ async fn main() -> Result<(), Box> { let settings = load_settings(); - let invehicle_digital_twin_url = match settings.invehicle_digital_twin_url { - Some(value) => value, - None => { - match settings.chariott_url { - Some(value) => { - match discover_digital_twin_service_using_chariott(&value).await { - Ok(Some(value)) => value, - Ok(None) => Err("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")?, - Err(error) => Err(format!("Failed to discover the in-vehicle digital twin service's URL due to error: {error}"))? - } - } - None => { - Err("The settings file must set a chariott_url setting when the invehicle_digital_twin_url is not set.")? - } - } - } - }; + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; // Setup the HTTP server. let consumer_authority = settings.consumer_authority; @@ -51,9 +61,10 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{consumer_authority}'"); - // Workarounhd: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str + // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); + // Retrieve the provider URI. let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( static_url_str, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, @@ -62,24 +73,20 @@ async fn main() -> Result<(), Box> { ) .await .unwrap(); - let provider_uri = provider_endpoint_info.uri; - info!("The URI for the AmbientAirTemperature property's provider is {provider_uri}"); + // Construct the consumer URI from the consumer authority. let consumer_uri = format!("http://{consumer_authority}"); // Devskim: ignore DS137138 - // Subscribing to the ambient air temperature data feed. info!( "Sending a subscribe request for entity id {} to provider URI {provider_uri}", sdv::vehicle::cabin::hvac::ambient_air_temperature::ID ); - let mut client = DigitalTwinProviderClient::connect(provider_uri).await?; - let request = tonic::Request::new(SubscribeRequest { - entity_id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - consumer_uri, - }); - let _response = client.subscribe(request).await?; + retry_async_based_on_status(30, Duration::from_secs(1), || { + subscribe_to_ambient_air_temperature(&provider_uri, &consumer_uri) + }) + .await?; server_future.await?; diff --git a/samples/protobuf_data_access/build.rs b/samples/protobuf_data_access/build.rs index d69f6596..3916ac05 100644 --- a/samples/protobuf_data_access/build.rs +++ b/samples/protobuf_data_access/build.rs @@ -12,16 +12,14 @@ fn main() -> Result<(), Box> { &["../../interfaces/digital_twin/v1/digital_twin.proto"], &["../../interfaces/digital_twin/v1/"], )?; - tonic_build::configure() - .compile( - &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], - &["../../external/chariott/proto"], - )?; - tonic_build::configure() - .compile( - &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], - &["../../external/chariott/proto"], - )?; + tonic_build::configure().compile( + &["../../external/chariott/proto/chariott/runtime/v1/runtime.proto"], + &["../../external/chariott/proto"], + )?; + tonic_build::configure().compile( + &["../../external/chariott/proto/chariott/provider/v1/provider.proto"], + &["../../external/chariott/proto"], + )?; Ok(()) } From f1804079536e0f2f967cc650171bebde07c41351 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:38:53 -0700 Subject: [PATCH 06/23] Use Chariott --- samples/command/consumer/src/main.rs | 28 ++++++--- samples/command/provider/src/main.rs | 73 ++++++++++++++++------- samples/property/consumer/src/main.rs | 3 +- samples/property/provider/src/main.rs | 85 +++++++++++++++++++-------- 4 files changed, 132 insertions(+), 57 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index dba3c1c3..7c376a46 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -8,7 +8,8 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::discover_digital_twin_provider_using_ibeji; +use samples_common::consumer_config::load_settings; +use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::InvokeRequest; @@ -17,9 +18,6 @@ use tokio::time::{sleep, Duration}; use tonic::transport::Server; use uuid::Uuid; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const CONSUMER_AUTHORITY: &str = "[::1]:60010"; - /// Start the show notification repeater. /// /// # Arguments @@ -72,15 +70,28 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); + let settings = load_settings(); + + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; + + let consumer_authority = settings.consumer_authority; + // Setup the HTTP server. - let addr: SocketAddr = CONSUMER_AUTHORITY.parse()?; + let addr: SocketAddr = consumer_authority.parse()?; let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); - info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{consumer_authority}'"); + + // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str + let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + static_url_str, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], @@ -91,8 +102,7 @@ async fn main() -> Result<(), Box> { let provider_uri = provider_endpoint_info.uri; info!("The URI for the ShowNotification command's provider is {provider_uri}"); - - let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 + let consumer_uri = format!("http://{consumer_authority}"); // Devskim: ignore DS137138 start_show_notification_repeater(provider_uri, consumer_uri); diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 8df94415..8be520ad 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -9,30 +9,31 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::provider_config::load_settings; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; -use tonic::transport::Server; +use tokio::time::Duration; +use tonic::{Status, transport::Server}; use crate::provider_impl::{ProviderImpl, SubscriptionMap}; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const PROVIDER_AUTHORITY: &str = "[::1]:40010"; - -#[tokio::main] -#[allow(clippy::collapsible_else_if)] -async fn main() -> Result<(), Box> { - // Setup logging. - Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); - - info!("The Provider has started."); - +/// Register the show notification commans's endpoint. +/// +/// # Arguments +/// * `invehicle_digital_twin_url` - The In-Vehicle Digital Twin URL. +/// * `provider_uri` - The provider's URI. +async fn register_show_notification( + invehicle_digital_twin_url: &str, + provider_uri: &str, +) -> Result<(), Status> { let endpoint_info = EndpointInfo { protocol: digital_twin_protocol::GRPC.to_string(), operations: vec![digital_twin_operation::INVOKE.to_string()], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), // Devskim: ignore DS137138 context: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), }; @@ -43,20 +44,50 @@ async fn main() -> Result<(), Box> { endpoint_info_list: vec![endpoint_info], }; + let mut client = DigitalTwinClient::connect(invehicle_digital_twin_url.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; + let request = + tonic::Request::new(RegisterRequest { entity_access_info_list: vec![entity_access_info] }); + let _response = client.register(request).await?; + + Ok(()) +} + +#[tokio::main] +#[allow(clippy::collapsible_else_if)] +async fn main() -> Result<(), Box> { + // Setup logging. + Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); + + info!("The Provider has started."); + + let settings = load_settings(); + + let provider_authority = settings.provider_authority; + + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; + + // Construct the provider URI from the provider authority. + let provider_uri = format!("http://{provider_authority}"); // Devskim: ignore DS137138 + // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; + let addr: SocketAddr = provider_authority.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); let provider_impl = ProviderImpl { subscription_map: subscription_map.clone() }; let server_future = Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); - info!("The HTTP server is listening on address '{PROVIDER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{provider_authority}'"); - info!("Sending a register request with the Provider's DTDL to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = - tonic::Request::new(RegisterRequest { entity_access_info_list: vec![entity_access_info] }); - let _response = client.register(request).await?; - debug!("The Provider's DTDL has been registered."); + info!("Sending a register request to the In-Vehicle Digital Twin Service URL {invehicle_digital_twin_url}"); + retry_async_based_on_status(30, Duration::from_secs(1), || { + register_show_notification(&invehicle_digital_twin_url, &provider_uri) + }) + .await?; server_future.await?; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 390da13f..f1bb13e9 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -53,8 +53,9 @@ async fn main() -> Result<(), Box> { ) .await?; - // Setup the HTTP server. let consumer_authority = settings.consumer_authority; + + // Setup the HTTP server. let addr: SocketAddr = consumer_authority.parse().unwrap(); let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index b0f80c59..b25d15df 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -9,6 +9,8 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::provider_config::load_settings; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; @@ -18,12 +20,48 @@ use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; use tokio::time::{sleep, Duration}; -use tonic::transport::Server; +use tonic::{Status, transport::Server}; use crate::provider_impl::{ProviderImpl, SubscriptionMap}; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://0.0.0.0:5010"; // Devskim: ignore DS137138 -const PROVIDER_AUTHORITY: &str = "0.0.0.0:4010"; +/// Register the ambient air temperature property's endpoint. +/// +/// # Arguments +/// * `invehicle_digital_twin_url` - The In-Vehicle Digital Twin URL. +/// * `provider_uri` - The provider's URI. +async fn register_ambient_air_temperature( + invehicle_digital_twin_url: &str, + provider_uri: &str, +) -> Result<(), Status> { + let endpoint_info = EndpointInfo { + protocol: digital_twin_protocol::GRPC.to_string(), + operations: vec![ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::UNSUBSCRIBE.to_string(), + ], + uri: provider_uri.to_string(), + context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + }; + + let entity_access_info = EntityAccessInfo { + name: "AmbientAirTemperature".to_string(), + id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + description: "The immediate surroundings air temperature (in Fahrenheit).".to_string(), + endpoint_info_list: vec![endpoint_info], + }; + + let mut client = DigitalTwinClient::connect(invehicle_digital_twin_url.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; + let request = + tonic::Request::new(RegisterRequest { entity_access_info_list: vec![entity_access_info] }); + let _response = client.register(request).await?; + + Ok(()) +} + +// const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://0.0.0.0:5010"; // Devskim: ignore DS137138 +// const PROVIDER_AUTHORITY: &str = "0.0.0.0:4010"; /// Start the ambient air temperature data stream. /// @@ -101,37 +139,32 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let endpoint_info = EndpointInfo { - protocol: digital_twin_protocol::GRPC.to_string(), - operations: vec![ - digital_twin_operation::SUBSCRIBE.to_string(), - digital_twin_operation::UNSUBSCRIBE.to_string(), - ], - uri: "http://0.0.0.0:4010".to_string(), // Devskim: ignore DS137138 - context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - }; + let settings = load_settings(); - let entity_access_info = EntityAccessInfo { - name: "AmbientAirTemperature".to_string(), - id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - description: "The immediate surroundings air temperature (in Fahrenheit).".to_string(), - endpoint_info_list: vec![endpoint_info], - }; + let provider_authority = settings.provider_authority; + + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; + + // Construct the provider URI from the provider authority. + let provider_uri = format!("http://{provider_authority}"); // Devskim: ignore DS137138 // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; + let addr: SocketAddr = provider_authority.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); let provider_impl = ProviderImpl { subscription_map: subscription_map.clone() }; let server_future = Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); - info!("The HTTP server is listening on address '{PROVIDER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{provider_authority}'"); - info!("Sending a register request with the Provider's DTDL to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = - tonic::Request::new(RegisterRequest { entity_access_info_list: vec![entity_access_info] }); - let _response = client.register(request).await?; - debug!("The Provider's DTDL has been registered."); + info!("Sending a register request wto the In-Vehicle Digital Twin Service URI {invehicle_digital_twin_url}"); + retry_async_based_on_status(30, Duration::from_secs(1), || { + register_ambient_air_temperature(&invehicle_digital_twin_url, &provider_uri) + }) + .await?; start_ambient_air_temperature_data_stream(subscription_map.clone()); From 96f41424afb4e2ff1f94800cdb3aedfc19108978 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 15:53:58 -0700 Subject: [PATCH 07/23] Use Chariott --- README.md | 54 ++++++-- samples/mixed/consumer/src/main.rs | 80 ++++++----- samples/mixed/provider/src/main.rs | 188 +++++++++++++++----------- samples/property/consumer/src/main.rs | 4 +- samples/property/provider/src/main.rs | 2 +- 5 files changed, 204 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 1f10c664..e8300080 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,18 @@ Steps: 1. The best way to run the demo is by using three windows: one running the In-Vehicle Digital Twin, one running the Provider and one running a Consumer. Orientate the three windows so that they are lined up in a column. The top window can be used for the In-Vehicle Digital Twin. The middle window can be used for the Provider. The bottom window can be used for a Consumer.
-1. In each window change directory to the directory containing the build artifacts. +1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
+1. Make sure that we have three config files with the following contents:

+---- consumer_settings.yaml ----
+consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

+---- invehicle_digital_twin_settings.yaml ----
+invehicle_digital_twin_authority: "0.0.0.0:5010"

+---- provider_settings.yaml ----
+provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -130,9 +139,18 @@ Steps: 1. The best way to run the demo is by using three windows: one running the In-Vehicle Digital Twin, one running the Provider and one running a Consumer. Orientate the three windows so that they are lined up in a column. The top window can be used for the In-Vehicle Digital Twin. The middle window can be used for the Provider. The bottom window can be used for a Consumer.
-1. In each window change directory to the directory containing the build artifacts. +1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
+1. Make sure that we have three config files with the following contents:

+---- consumer_settings.yaml ----
+consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

+---- invehicle_digital_twin_settings.yaml ----
+invehicle_digital_twin_authority: "0.0.0.0:5010"

+---- provider_settings.yaml ----
+provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -141,14 +159,6 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `./command-consumer`
1. Use control-c in each of the windows when you wish to stop the demo. -## Trademarks - -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow -[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). -Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. -Any use of third-party trademarks or logos are subject to those third-party's policies. - The following instructions are for the demo for the mixed use of commands and properties. Steps: @@ -156,9 +166,18 @@ Steps: 1. The best way to run the demo is by using three windows: one running the In-Vehicle Digital Twin, one running the Provider and one running a Consumer. Orientate the three windows so that they are lined up in a column. The top window can be used for the In-Vehicle Digital Twin. The middle window can be used for the Provider. The bottom window can be used for a Consumer.
-1. In each window change directory to the directory containing the build artifacts. +1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
+1. Make sure that we have three config files with the following contents:

+---- consumer_settings.yaml ----
+consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

+---- invehicle_digital_twin_settings.yaml ----
+invehicle_digital_twin_authority: "0.0.0.0:5010"

+---- provider_settings.yaml ----
+provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -167,6 +186,19 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `./mixed-consumer`
1. Use control-c in each of the windows when you wish to stop the demo. +If you want the consumers and providers for each demo to use Chariott to discover the URL for the In-Vehicle Digital Twin Service, rather than +having it statically provided in their respective config file, then do the following before starting each demo: + +1. Clone a copy of Chariott from GitHub (https://github.com/eclipse-chariott/chariott). +1. Build Chariott +1. Set Chariott's CHARIOTT_REGISTRY_TTL_SECS environment variable to a high number (we suggest 86400 seconds), as Ibeji does not rely on Chariott's announce feature:

+`export CHARIOTT_REGISTRY_TTL_SECS=86400`
+1. Run Chariott:

+`cargo run -p chariott`
+1. In each of the the config files, add the setting:

+`chariott_url: "http://0.0.0.0:4243"`
+1. In the consumer's config file and the provider's config file, comment out the setting for invehicle_digital_twin_url, so that the chariott_url will be used to find the In-vehicle Digital Twin URL.
+ ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 17b64249..63c94273 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -8,7 +8,8 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::discover_digital_twin_provider_using_ibeji; +use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::consumer_config::load_settings; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::{ @@ -16,13 +17,9 @@ use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::{ }; use std::net::SocketAddr; use tokio::time::{sleep, Duration}; -use tonic::transport::Server; +use tonic::{Status, transport::Server}; use uuid::Uuid; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 - -const CONSUMER_AUTHORITY: &str = "[::1]:60010"; - /// Start the show-notification repeater. /// /// # Arguments @@ -118,9 +115,11 @@ async fn send_subscribe_request( provider_uri: &str, entity_id: &str, consumer_uri: &str, -) -> Result<(), Box> { +) -> Result<(), Status> { info!("Sending a subscribe request for entity id {entity_id} to provider URI {provider_uri}"); - let mut client = DigitalTwinProviderClient::connect(provider_uri.to_string()).await?; + let mut client = DigitalTwinProviderClient::connect(provider_uri.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; let request = tonic::Request::new(SubscribeRequest { entity_id: entity_id.to_string(), consumer_uri: consumer_uri.to_string(), @@ -137,16 +136,31 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); + let settings = load_settings(); + + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; + + let consumer_authority = settings.consumer_authority; + + let consumer_uri = format!("http://{consumer_authority}"); // Devskim: ignore DS137138 + // Setup the HTTP server. - let addr: SocketAddr = CONSUMER_AUTHORITY.parse()?; + let addr: SocketAddr = consumer_authority.parse()?; let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); - info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{consumer_authority}'"); + + // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str + let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); let show_notification_command_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + static_url_str, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], @@ -158,7 +172,7 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + static_url_str, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], @@ -170,7 +184,7 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + static_url_str, sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, digital_twin_protocol::GRPC, &[ @@ -185,7 +199,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - IN_VEHICLE_DIGITAL_TWIN_SERVICE_URL, + static_url_str, sdv::vehicle::obd::hybrid_battery_remaining::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], @@ -195,27 +209,31 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_provider_uri = hybrid_battery_remaining_property_provider_endpoint_info.uri; - let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 - - send_subscribe_request( - &ambient_air_temperature_property_provider_uri, - sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, - &consumer_uri, - ) + retry_async_based_on_status(30, Duration::from_secs(1), || { + send_subscribe_request( + &ambient_air_temperature_property_provider_uri, + sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, + &consumer_uri, + ) + }) .await?; - send_subscribe_request( - &is_air_conditioning_active_property_provider_uri, - sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, - &consumer_uri, - ) + retry_async_based_on_status(30, Duration::from_secs(1), || { + send_subscribe_request( + &is_air_conditioning_active_property_provider_uri, + sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, + &consumer_uri, + ) + }) .await?; - send_subscribe_request( - &hybrid_battery_remaining_property_provider_uri, - sdv::vehicle::obd::hybrid_battery_remaining::ID, - &consumer_uri, - ) + retry_async_based_on_status(30, Duration::from_secs(1), || { + send_subscribe_request( + &hybrid_battery_remaining_property_provider_uri, + sdv::vehicle::obd::hybrid_battery_remaining::ID, + &consumer_uri, + ) + }) .await?; start_activate_air_conditioning_repeater(is_air_conditioning_active_property_provider_uri); diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 2d83c8b1..0bf72979 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -10,6 +10,8 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; +use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::provider_config::load_settings; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; @@ -19,13 +21,101 @@ use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; use tokio::time::{sleep, Duration}; -use tonic::transport::Server; +use tonic::{Status, transport::Server}; use crate::provider_impl::{ProviderImpl, SubscriptionMap}; use crate::vehicle::Vehicle; -const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const PROVIDER_AUTHORITY: &str = "[::1]:40010"; +/// Register the entities endpoints. +/// +/// # Arguments +/// * `invehicle_digital_twin_url` - The In-Vehicle Digital Twin URL. +/// * `provider_uri` - The provider's URI. +async fn register_entities( + invehicle_digital_twin_url: &str, + provider_uri: &str, +) -> Result<(), Status> { + // AmbientAirTemperature + let ambient_air_temperature_endpoint_info = EndpointInfo { + protocol: digital_twin_protocol::GRPC.to_string(), + operations: vec![ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::UNSUBSCRIBE.to_string(), + ], + uri: provider_uri.to_string(), // Devskim: ignore DS137138 + context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + }; + let ambient_air_temperature_access_info = EntityAccessInfo { + name: "AmbientAirTemperature".to_string(), + id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + description: "The immediate surroundings air temperature (in Fahrenheit).".to_string(), + endpoint_info_list: vec![ambient_air_temperature_endpoint_info], + }; + + // IsAirConditioningActive + let is_air_conditioning_active_endpoint_info = EndpointInfo { + protocol: digital_twin_protocol::GRPC.to_string(), + operations: vec![ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::UNSUBSCRIBE.to_string(), + digital_twin_operation::SET.to_string(), + ], + uri: provider_uri.to_string(), // Devskim: ignore DS137138 + context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), + }; + let is_air_conditioning_active_access_info = EntityAccessInfo { + name: "IsAirConditioningActive".to_string(), + id: sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID.to_string(), + description: "Is air conditioning active?".to_string(), + endpoint_info_list: vec![is_air_conditioning_active_endpoint_info], + }; + + // HybridBatteryRemaining + let hybrid_battery_remaining_endpoint_info = EndpointInfo { + protocol: digital_twin_protocol::GRPC.to_string(), + operations: vec![ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::UNSUBSCRIBE.to_string(), + ], + uri: provider_uri.to_string(), // Devskim: ignore DS137138 + context: sdv::vehicle::obd::hybrid_battery_remaining::ID.to_string(), + }; + let hybrid_battery_remaining_access_info = EntityAccessInfo { + name: "HybridBatteryRemaining".to_string(), + id: sdv::vehicle::obd::hybrid_battery_remaining::ID.to_string(), + description: "The remaining hybrid battery life.".to_string(), + endpoint_info_list: vec![hybrid_battery_remaining_endpoint_info], + }; + + // ShowNotification + let show_notification_endpoint_info = EndpointInfo { + protocol: digital_twin_protocol::GRPC.to_string(), + operations: vec![digital_twin_operation::INVOKE.to_string()], + uri: provider_uri.to_string(), // Devskim: ignore DS137138 + context: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), + }; + let show_notification_access_info = EntityAccessInfo { + name: "ShowNotification".to_string(), + id: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), + description: "Show a notification on the HMI.".to_string(), + endpoint_info_list: vec![show_notification_endpoint_info], + }; + + let entity_access_info_list = vec![ + ambient_air_temperature_access_info, + is_air_conditioning_active_access_info, + hybrid_battery_remaining_access_info, + show_notification_access_info, + ]; + + let mut client = DigitalTwinClient::connect(invehicle_digital_twin_url.to_string()) + .await + .map_err(|e| Status::internal(e.to_string()))?; + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); + let _response = client.register(request).await?; + + Ok(()) +} async fn publish(subscription_map: Arc>, entity_id: &str, value: &str) { let urls; @@ -124,94 +214,34 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - // AmbientAirTemperature - let ambient_air_temperature_endpoint_info = EndpointInfo { - protocol: digital_twin_protocol::GRPC.to_string(), - operations: vec![ - digital_twin_operation::SUBSCRIBE.to_string(), - digital_twin_operation::UNSUBSCRIBE.to_string(), - ], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 - context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - }; - let ambient_air_temperature_access_info = EntityAccessInfo { - name: "AmbientAirTemperature".to_string(), - id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - description: "The immediate surroundings air temperature (in Fahrenheit).".to_string(), - endpoint_info_list: vec![ambient_air_temperature_endpoint_info], - }; - - // IsAirConditioningActive - let is_air_conditioning_active_endpoint_info = EndpointInfo { - protocol: digital_twin_protocol::GRPC.to_string(), - operations: vec![ - digital_twin_operation::SUBSCRIBE.to_string(), - digital_twin_operation::UNSUBSCRIBE.to_string(), - digital_twin_operation::SET.to_string(), - ], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 - context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), - }; - let is_air_conditioning_active_access_info = EntityAccessInfo { - name: "IsAirConditioningActive".to_string(), - id: sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID.to_string(), - description: "Is air conditioning active?".to_string(), - endpoint_info_list: vec![is_air_conditioning_active_endpoint_info], - }; + let settings = load_settings(); - // HybridBatteryRemaining - let hybrid_battery_remaining_endpoint_info = EndpointInfo { - protocol: digital_twin_protocol::GRPC.to_string(), - operations: vec![ - digital_twin_operation::SUBSCRIBE.to_string(), - digital_twin_operation::UNSUBSCRIBE.to_string(), - ], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 - context: sdv::vehicle::obd::hybrid_battery_remaining::ID.to_string(), - }; - let hybrid_battery_remaining_access_info = EntityAccessInfo { - name: "HybridBatteryRemaining".to_string(), - id: sdv::vehicle::obd::hybrid_battery_remaining::ID.to_string(), - description: "The remaining hybrid battery life.".to_string(), - endpoint_info_list: vec![hybrid_battery_remaining_endpoint_info], - }; + let provider_authority = settings.provider_authority; - // ShowNotification - let show_notification_endpoint_info = EndpointInfo { - protocol: digital_twin_protocol::GRPC.to_string(), - operations: vec![digital_twin_operation::INVOKE.to_string()], - uri: "http://[::1]:40010".to_string(), // Devskim: ignore DS137138 - context: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), - }; - let show_notification_access_info = EntityAccessInfo { - name: "ShowNotification".to_string(), - id: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), - description: "Show a notification on the HMI.".to_string(), - endpoint_info_list: vec![show_notification_endpoint_info], - }; + let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( + settings.invehicle_digital_twin_url, + settings.chariott_url, + ) + .await?; - let entity_access_info_list = vec![ - ambient_air_temperature_access_info, - is_air_conditioning_active_access_info, - hybrid_battery_remaining_access_info, - show_notification_access_info, - ]; + // Construct the provider URI from the provider authority. + let provider_uri = format!("http://{provider_authority}"); // Devskim: ignore DS137138 // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; + let addr: SocketAddr = provider_authority.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); let vehicle = Arc::new(Mutex::new(Vehicle::new())); let provider_impl = ProviderImpl { subscription_map: subscription_map.clone(), vehicle: vehicle.clone() }; let server_future = Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); - info!("The HTTP server is listening on address '{PROVIDER_AUTHORITY}'"); + info!("The HTTP server is listening on address '{provider_authority}'"); - info!("Sending a register request with the Provider's entity access info to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); - let _response = client.register(request).await?; - debug!("The Provider's entity access info has been registered."); + info!("Sending a register request to the In-Vehicle Digital Twin Service URI {invehicle_digital_twin_url}"); + retry_async_based_on_status(30, Duration::from_secs(1), || { + register_entities(&invehicle_digital_twin_url, &provider_uri) + }) + .await?; start_vehicle_simulator(subscription_map.clone(), vehicle).await; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index f1bb13e9..3d605f05 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -2,6 +2,8 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +mod consumer_impl; + use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; @@ -15,8 +17,6 @@ use std::net::SocketAddr; use tokio::time::Duration; use tonic::{Status, transport::Server}; -mod consumer_impl; - /// Subscribe to the ambient air temperature. /// /// # Arguments diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index b25d15df..6e786296 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -160,7 +160,7 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); info!("The HTTP server is listening on address '{provider_authority}'"); - info!("Sending a register request wto the In-Vehicle Digital Twin Service URI {invehicle_digital_twin_url}"); + info!("Sending a register request to the In-Vehicle Digital Twin Service URI {invehicle_digital_twin_url}"); retry_async_based_on_status(30, Duration::from_secs(1), || { register_ambient_air_temperature(&invehicle_digital_twin_url, &provider_uri) }) From a4aae1aab05b459187429af3615bc1d670c775de Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:10:20 -0700 Subject: [PATCH 08/23] Use Chariott --- .accepted_words.txt | 8 ++++++++ Cargo.toml | 2 +- core/invehicle-digital-twin/src/main.rs | 4 ++-- core/invehicle-digital-twin/src/providerservice_impl.rs | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.accepted_words.txt b/.accepted_words.txt index 271a56b4..0a315401 100644 --- a/.accepted_words.txt +++ b/.accepted_words.txt @@ -2,7 +2,12 @@ br build cargo cd +CHARIOTT +Chariott +Chariott's +chariott com +config digitaltwins dir dt @@ -19,6 +24,7 @@ ibeji Ibeji Ibeji's intellectualproperty +invehicle iot js json @@ -39,4 +45,6 @@ snapd sudo timothee toolchain +url www +yaml diff --git a/Cargo.toml b/Cargo.toml index aa782ad6..559ba947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ prost = "0.11" prost-types = "0.11" regex = " 1.8.3" serde = "1.0.160" -serde_derive = "1.0.163" +serde_derive = "1.0.163" serde_json = "^1.0" strum = "0.24" strum_macros = "0.24" diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 4e6f7d6a..42c2521f 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -56,13 +56,13 @@ pub async fn register_digital_twin_service_with_chariott( let response = client.register(request).await; - if !response.is_ok() { + if response.is_err() { return Err(Status::internal("Chariott register request failed")); } info!("{:?}", response.unwrap().into_inner()); - return Ok(()); + Ok(()) } #[tokio::main] diff --git a/core/invehicle-digital-twin/src/providerservice_impl.rs b/core/invehicle-digital-twin/src/providerservice_impl.rs index ee053443..daf54b49 100644 --- a/core/invehicle-digital-twin/src/providerservice_impl.rs +++ b/core/invehicle-digital-twin/src/providerservice_impl.rs @@ -74,7 +74,7 @@ mod providerservice_impl_tests { #[tokio::test] async fn fulfill_test() { let provider_service_impl = - ProviderServiceImpl { url: Url::parse("http://0.0.0.0:80").unwrap() }; + ProviderServiceImpl { url: Url::parse("http://0.0.0.0:80").unwrap() }; // Devskim: ignore DS137138 let request = Request::new(FulfillRequest { intent: Some(IntentMessage { intent: Some(IntentEnum::Discover(DiscoverIntent {})) }), From 87c79b5db10a960306690e6e226505dedefa8e12 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:18:53 -0700 Subject: [PATCH 09/23] Use Chariott --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e8300080..3cc03e75 100644 --- a/README.md +++ b/README.md @@ -117,13 +117,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` ---- invehicle_digital_twin_settings.yaml ----
-invehicle_digital_twin_authority: "0.0.0.0:5010"

+`invehicle_digital_twin_authority: "0.0.0.0:5010"

` ---- provider_settings.yaml ----
-provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` 1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -144,13 +144,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` ---- invehicle_digital_twin_settings.yaml ----
-invehicle_digital_twin_authority: "0.0.0.0:5010"

+`invehicle_digital_twin_authority: "0.0.0.0:5010"

` ---- provider_settings.yaml ----
-provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` 1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -171,13 +171,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`consumer_authority: "0.0.0.0:6010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` ---- invehicle_digital_twin_settings.yaml ----
-invehicle_digital_twin_authority: "0.0.0.0:5010"

+`invehicle_digital_twin_authority: "0.0.0.0:5010"

` ---- provider_settings.yaml ----
-provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

+`provider_authority: "0.0.0.0:4010"
+invehicle_digital_twin_url: "http://0.0.0.0:5010"

` 1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

From 57dbbc2e88e90a0482ab6ff32c97899a96bab1fd Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:22:54 -0700 Subject: [PATCH 10/23] Use Chariott --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3cc03e75..75ccf81e 100644 --- a/README.md +++ b/README.md @@ -117,13 +117,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-`consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`consumer_authority: "0.0.0.0:6010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

---- invehicle_digital_twin_settings.yaml ----
-`invehicle_digital_twin_authority: "0.0.0.0:5010"

` +`invehicle_digital_twin_authority: "0.0.0.0:5010"`

---- provider_settings.yaml ----
-`provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`provider_authority: "0.0.0.0:4010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -144,13 +144,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-`consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`consumer_authority: "0.0.0.0:6010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

---- invehicle_digital_twin_settings.yaml ----
-`invehicle_digital_twin_authority: "0.0.0.0:5010"

` +`invehicle_digital_twin_authority: "0.0.0.0:5010"`

---- provider_settings.yaml ----
-`provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`provider_authority: "0.0.0.0:4010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -171,13 +171,13 @@ Make sure that you replace "{repo-root-dir}" with the repository root directory `cd {repo-root-dir}/target/debug`
1. Make sure that we have three config files with the following contents:

---- consumer_settings.yaml ----
-`consumer_authority: "0.0.0.0:6010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`consumer_authority: "0.0.0.0:6010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

---- invehicle_digital_twin_settings.yaml ----
-`invehicle_digital_twin_authority: "0.0.0.0:5010"

` +`invehicle_digital_twin_authority: "0.0.0.0:5010"`

---- provider_settings.yaml ----
-`provider_authority: "0.0.0.0:4010"
-invehicle_digital_twin_url: "http://0.0.0.0:5010"

` +`provider_authority: "0.0.0.0:4010"`
+`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

1. In the top window, run:

`./in-vehicle-digital-twin`
1. In the middle window, run:

@@ -189,7 +189,7 @@ invehicle_digital_twin_url: "http://0.0.0.0:5010"

` If you want the consumers and providers for each demo to use Chariott to discover the URL for the In-Vehicle Digital Twin Service, rather than having it statically provided in their respective config file, then do the following before starting each demo: -1. Clone a copy of Chariott from GitHub (https://github.com/eclipse-chariott/chariott). +1. Clone a copy of Chariott from GitHub (`https://github.com/eclipse-chariott/chariott`). 1. Build Chariott 1. Set Chariott's CHARIOTT_REGISTRY_TTL_SECS environment variable to a high number (we suggest 86400 seconds), as Ibeji does not rely on Chariott's announce feature:

`export CHARIOTT_REGISTRY_TTL_SECS=86400`
From 37b4cc0472197070fafcdbefcbf2ea8150ced867 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:32:11 -0700 Subject: [PATCH 11/23] Use Chariott --- samples/common/src/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index 774e1c1e..0dbd0048 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -152,7 +152,7 @@ pub async fn discover_digital_twin_service_using_chariott( if services.is_some() { for service in services.unwrap() { if service.schema_kind == CHARIOTT_SCHEMA_KIND_FOR_GRPC { - return Ok(Some(service.url.to_string())); + return Ok(Some(service.url)); } } } From 54680c51e26db843cb976f3035b99738a7c70834 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sat, 3 Jun 2023 17:51:23 -0700 Subject: [PATCH 12/23] Use Chariott --- Cargo.toml | 1 - README.md | 2 +- .../src/invehicle_digital_twin_config.rs | 1 + samples/common/Cargo.toml | 1 - samples/common/src/consumer_config.rs | 1 + samples/common/src/misc.rs | 11 +++++++++-- samples/common/src/provider_config.rs | 1 + 7 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 559ba947..b501875a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ members = [ async-std = "^1.5" config = "0.13.3" env_logger= "0.10.0" -fixed = "1.23.1" futures = "0.3" generic-json = "^0.7" iref = "^2.0.3" diff --git a/README.md b/README.md index 75ccf81e..45fc8b17 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ having it statically provided in their respective config file, then do the follo `cargo run -p chariott`
1. In each of the the config files, add the setting:

`chariott_url: "http://0.0.0.0:4243"`
-1. In the consumer's config file and the provider's config file, comment out the setting for invehicle_digital_twin_url, so that the chariott_url will be used to find the In-vehicle Digital Twin URL.
+1. In the consumer's config file and the provider's config file, remove the setting for invehicle_digital_twin_url, so that the chariott_url will be used to find the In-vehicle Digital Twin URL.
## Trademarks diff --git a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs index b53b2a66..34d4f758 100644 --- a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs +++ b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs @@ -13,6 +13,7 @@ pub struct Settings { pub chariott_url: Option, } +/// Load the settings. pub fn load_settings() -> Settings { let config = Config::builder() .add_source(File::new("invehicle_digital_twin_settings", FileFormat::Yaml)) diff --git a/samples/common/Cargo.toml b/samples/common/Cargo.toml index 275edaa2..fb69f10e 100644 --- a/samples/common/Cargo.toml +++ b/samples/common/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] config = { workspace = true } -fixed = { workspace = true } log = { workspace = true } samples-protobuf-data-access = { path = "../protobuf_data_access" } serde = { workspace = true, features = ["derive"] } diff --git a/samples/common/src/consumer_config.rs b/samples/common/src/consumer_config.rs index bc73068f..fcd34ad9 100644 --- a/samples/common/src/consumer_config.rs +++ b/samples/common/src/consumer_config.rs @@ -14,6 +14,7 @@ pub struct Settings { pub invehicle_digital_twin_url: Option, } +/// Load the settings. pub fn load_settings() -> Settings { let config = Config::builder() .add_source(File::new("consumer_settings", FileFormat::Yaml)) diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index 0dbd0048..f228b676 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -14,11 +14,11 @@ use samples_protobuf_data_access::chariott::{ use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, FindByIdRequest}; use std::future::Future; -use tonic::{Code, Request, Status}; - use tokio::time::{sleep, Duration}; +use tonic::{Code, Request, Status}; pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; + pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; /// Is the provided subset a subset of the provided superset? @@ -160,6 +160,13 @@ pub async fn discover_digital_twin_service_using_chariott( Ok(None) } +/// Retrieve the In-Vehicle Digital Twin URL. +/// If invehicle_digital_twin_url is provided, then it's bvalue is returned. +/// Otherwise, chariott_url is used to retrieve it from Chariott. +/// +/// # Arguments +/// * `invehicle_digital_twin_url` - Optional, In-Vehicle Digital Twin URL. +/// * `chariott_url` - Optional, Chariott URL. pub async fn retrieve_invehicle_digital_twin_url( invehicle_digital_twin_url: Option, chariott_url: Option, diff --git a/samples/common/src/provider_config.rs b/samples/common/src/provider_config.rs index 816b9906..86879bf4 100644 --- a/samples/common/src/provider_config.rs +++ b/samples/common/src/provider_config.rs @@ -14,6 +14,7 @@ pub struct Settings { pub invehicle_digital_twin_url: Option, } +/// Load the settings. pub fn load_settings() -> Settings { let config = Config::builder() .add_source(File::new("provider_settings", FileFormat::Yaml)) From ba79a576af754e0909e8e53d40f0b08d839240a9 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 4 Jun 2023 22:50:32 -0700 Subject: [PATCH 13/23] Use Chariott --- samples/command/consumer/src/main.rs | 5 +---- samples/command/provider/src/main.rs | 4 ++-- samples/common/src/constants.rs | 7 +++++- samples/common/src/lib.rs | 2 -- samples/common/src/misc.rs | 31 ++++++++++++--------------- samples/mixed/consumer/src/main.rs | 11 ++++------ samples/mixed/provider/src/main.rs | 8 +++---- samples/property/consumer/src/main.rs | 5 +---- samples/property/provider/src/main.rs | 3 --- 9 files changed, 32 insertions(+), 44 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 7c376a46..5797a654 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -87,11 +87,8 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{consumer_authority}'"); - // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str - let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); - let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 8be520ad..ce5f1a1d 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -21,7 +21,7 @@ use tonic::{Status, transport::Server}; use crate::provider_impl::{ProviderImpl, SubscriptionMap}; -/// Register the show notification commans's endpoint. +/// Register the show notification command's endpoint. /// /// # Arguments /// * `invehicle_digital_twin_url` - The In-Vehicle Digital Twin URL. @@ -33,7 +33,7 @@ async fn register_show_notification( let endpoint_info = EndpointInfo { protocol: digital_twin_protocol::GRPC.to_string(), operations: vec![digital_twin_operation::INVOKE.to_string()], - uri: provider_uri.to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), context: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), }; diff --git a/samples/common/src/constants.rs b/samples/common/src/constants.rs index 5fccfcf7..82bade71 100644 --- a/samples/common/src/constants.rs +++ b/samples/common/src/constants.rs @@ -11,7 +11,12 @@ pub mod digital_twin_operation { pub const INVOKE: &str = "Invoke"; } -// Supported gitial twin protocols. +// Supported digital twin protocols. pub mod digital_twin_protocol { pub const GRPC: &str = "grpc"; } + +pub mod chariott { + pub const NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; + pub const SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; +} diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 225026c9..1397f74a 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -2,8 +2,6 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -#![feature(async_closure)] - pub mod constants; pub mod consumer_config; pub mod misc; diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index f228b676..10c0ce70 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -2,6 +2,8 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +use crate::constants; + use log::{debug, info}; use samples_protobuf_data_access::chariott::runtime::v1::chariott_service_client::ChariottServiceClient; use samples_protobuf_data_access::chariott::{ @@ -17,10 +19,6 @@ use std::future::Future; use tokio::time::{sleep, Duration}; use tonic::{Code, Request, Status}; -pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; - -pub const CHARIOTT_SCHEMA_KIND_FOR_GRPC: &str = "grpc+proto"; - /// Is the provided subset a subset of the provided superset? /// /// # Arguments @@ -36,9 +34,9 @@ pub fn is_subset(subset: &[String], superset: &[String]) -> bool { /// Retry an async function that uses tonic::Status in for its error result. /// /// # Arguments -/// * `max_retries` - The maximu number of retries. +/// * `max_retries` - The maximum number of retries. /// * `duration_between_attempts` - The duration of time attempts. -/// * `function` - THe function. +/// * `function` - The function. pub async fn retry_async_based_on_status Fut>( max_retries: i32, duration_between_attempts: Duration, @@ -76,18 +74,18 @@ where /// Use Ibeji to discover the endpoint for a digital twin provider that satifies the requirements. /// /// # Arguments -/// * `invehcile_digitial_twin_servuce_url` - In-vehicle digital twin service URL. +/// * `invehicle_digitial_twin_servuce_url` - In-vehicle digital twin service URL. /// * `entity_id` - The matching entity id. /// * `protocol` - The required protocol. /// * `operations` - The required operations. pub async fn discover_digital_twin_provider_using_ibeji( - invehicle_digitial_twin_servuce_url: &'static str, + invehicle_digitial_twin_servuce_url: &str, entity_id: &str, protocol: &str, operations: &[String], ) -> Result { info!("Sending a find_by_id request for entity id {entity_id} to the In-Vehicle Digital Twin Service URL {invehicle_digitial_twin_servuce_url}"); - let mut client = DigitalTwinClient::connect(invehicle_digitial_twin_servuce_url) + let mut client = DigitalTwinClient::connect(invehicle_digitial_twin_servuce_url.to_string()) .await .map_err(|error| format!("{error}"))?; let request = tonic::Request::new(FindByIdRequest { id: entity_id.to_string() }); @@ -126,13 +124,13 @@ pub async fn discover_digital_twin_provider_using_ibeji( /// * `chariott_url` - Chariott's URL. pub async fn discover_digital_twin_service_using_chariott( chariott_url: &str, -) -> Result, Status> { +) -> Result { let mut client = ChariottServiceClient::connect(chariott_url.to_string()) .await .map_err(|e| Status::internal(e.to_string()))?; let request = Request::new(FulfillRequest { - namespace: CHARIOTT_NAMESPACE_FOR_IBEJI.to_string(), + namespace: constants::chariott::NAMESPACE_FOR_IBEJI.to_string(), intent: Some(IntentMessage { intent: Some(IntentEnum::Discover(DiscoverIntent {})) }), }); @@ -151,17 +149,17 @@ pub async fn discover_digital_twin_service_using_chariott( // If we discovered one or more service, then return the URL for the first one that uses gRPC. if services.is_some() { for service in services.unwrap() { - if service.schema_kind == CHARIOTT_SCHEMA_KIND_FOR_GRPC { - return Ok(Some(service.url)); + if service.schema_kind == constants::chariott::SCHEMA_KIND_FOR_GRPC { + return Ok(service.url); } } } - Ok(None) + Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) } /// Retrieve the In-Vehicle Digital Twin URL. -/// If invehicle_digital_twin_url is provided, then it's bvalue is returned. +/// If invehicle_digital_twin_url is provided, then it's value is returned. /// Otherwise, chariott_url is used to retrieve it from Chariott. /// /// # Arguments @@ -180,8 +178,7 @@ pub async fn retrieve_invehicle_digital_twin_url( match chariott_url { Some(value) => { match retry_async_based_on_status(30, Duration::from_secs(1), || discover_digital_twin_service_using_chariott(&value)).await { - Ok(Some(value)) => value, - Ok(None) => Err("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")?, + Ok(value) => value, Err(error) => Err(format!("Failed to discover the in-vehicle digital twin service's URL due to error: {error}"))? } } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 63c94273..b60ce689 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -155,12 +155,9 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{consumer_authority}'"); - // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str - let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); - let show_notification_command_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], @@ -172,7 +169,7 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], @@ -184,7 +181,7 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, digital_twin_protocol::GRPC, &[ @@ -199,7 +196,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::obd::hybrid_battery_remaining::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 0bf72979..31a01c10 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -42,7 +42,7 @@ async fn register_entities( digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::UNSUBSCRIBE.to_string(), ], - uri: provider_uri.to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), }; let ambient_air_temperature_access_info = EntityAccessInfo { @@ -60,7 +60,7 @@ async fn register_entities( digital_twin_operation::UNSUBSCRIBE.to_string(), digital_twin_operation::SET.to_string(), ], - uri: provider_uri.to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), context: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), }; let is_air_conditioning_active_access_info = EntityAccessInfo { @@ -77,7 +77,7 @@ async fn register_entities( digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::UNSUBSCRIBE.to_string(), ], - uri: provider_uri.to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), context: sdv::vehicle::obd::hybrid_battery_remaining::ID.to_string(), }; let hybrid_battery_remaining_access_info = EntityAccessInfo { @@ -91,7 +91,7 @@ async fn register_entities( let show_notification_endpoint_info = EndpointInfo { protocol: digital_twin_protocol::GRPC.to_string(), operations: vec![digital_twin_operation::INVOKE.to_string()], - uri: provider_uri.to_string(), // Devskim: ignore DS137138 + uri: provider_uri.to_string(), context: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID.to_string(), }; let show_notification_access_info = EntityAccessInfo { diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 3d605f05..9b96369c 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -62,12 +62,9 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{consumer_authority}'"); - // This is a workaround: see https://stackoverflow.com/questions/23975391/how-to-convert-a-string-into-a-static-str - let static_url_str = Box::leak(invehicle_digital_twin_url.into_boxed_str()); - // Retrieve the provider URI. let provider_endpoint_info = discover_digital_twin_provider_using_ibeji( - static_url_str, + &invehicle_digital_twin_url, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 6e786296..70ed13f6 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -60,9 +60,6 @@ async fn register_ambient_air_temperature( Ok(()) } -// const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://0.0.0.0:5010"; // Devskim: ignore DS137138 -// const PROVIDER_AUTHORITY: &str = "0.0.0.0:4010"; - /// Start the ambient air temperature data stream. /// /// # Arguments From 3503693dbf973fb0f0c009504b58bf1eed5ae80b Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:57:57 -0700 Subject: [PATCH 14/23] Use Chariott --- README.md | 6 +++--- .../src/invehicle_digital_twin_config.rs | 8 ++++---- core/invehicle-digital-twin/src/main.rs | 5 ++++- .../template/invehicle_digital_twin_settings.yaml | 11 +++++++++++ samples/command/consumer/src/main.rs | 4 ++-- samples/command/provider/src/main.rs | 4 ++-- samples/common/src/consumer_config.rs | 8 ++++---- samples/common/src/misc.rs | 5 +++-- samples/common/src/provider_config.rs | 8 ++++---- samples/common/template/consumer_settings.yaml | 14 ++++++++++++++ samples/common/template/provider_settings.yaml | 14 ++++++++++++++ samples/mixed/consumer/src/main.rs | 4 ++-- samples/mixed/provider/src/main.rs | 4 ++-- samples/property/consumer/src/main.rs | 4 ++-- samples/property/provider/src/main.rs | 4 ++-- 15 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml create mode 100644 samples/common/template/consumer_settings.yaml create mode 100644 samples/common/template/provider_settings.yaml diff --git a/README.md b/README.md index 45fc8b17..c2992ade 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ The middle window can be used for the Provider. The bottom window can be used fo 1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
-1. Make sure that we have three config files with the following contents:

+1. Create the three config files with the following contents, if they are not already there:

---- consumer_settings.yaml ----
`consumer_authority: "0.0.0.0:6010"`
`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

@@ -142,7 +142,7 @@ The middle window can be used for the Provider. The bottom window can be used fo 1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
-1. Make sure that we have three config files with the following contents:

+1. Create the three config files with the following contents, if they are not already there:

---- consumer_settings.yaml ----
`consumer_authority: "0.0.0.0:6010"`
`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

@@ -169,7 +169,7 @@ The middle window can be used for the Provider. The bottom window can be used fo 1. In each window, change directory to the directory containing the build artifacts. Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

`cd {repo-root-dir}/target/debug`
-1. Make sure that we have three config files with the following contents:

+1. Create the three config files with the following contents, if they are not already there:

---- consumer_settings.yaml ----
`consumer_authority: "0.0.0.0:6010"`
`invehicle_digital_twin_url: "http://0.0.0.0:5010"`

diff --git a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs index 34d4f758..50e0dd56 100644 --- a/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs +++ b/core/invehicle-digital-twin/src/invehicle_digital_twin_config.rs @@ -7,6 +7,8 @@ use config::{Config, File, FileFormat}; use serde_derive::Deserialize; +const CONFIG_FILENAME: &str = "invehicle_digital_twin_settings"; + #[derive(Debug, Deserialize)] pub struct Settings { pub invehicle_digital_twin_authority: String, @@ -15,10 +17,8 @@ pub struct Settings { /// Load the settings. pub fn load_settings() -> Settings { - let config = Config::builder() - .add_source(File::new("invehicle_digital_twin_settings", FileFormat::Yaml)) - .build() - .unwrap(); + let config = + Config::builder().add_source(File::new(CONFIG_FILENAME, FileFormat::Yaml)).build().unwrap(); let settings: Settings = config.try_deserialize().unwrap(); diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 42c2521f..5bd8dba3 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -31,7 +31,7 @@ pub const CHARIOTT_NAMESPACE_FOR_IBEJI: &str = "sdv.ibeji"; /// /// # Arguments /// * `chariott_url` - Chariott's URL. -/// * `invehicle_digital_twin_url` - In-vehcile Digital Twin Service's URL. +/// * `invehicle_digital_twin_url` - In-vehicle Digital Twin Service's URL. pub async fn register_digital_twin_service_with_chariott( chariott_url: &str, invehicle_digital_twin_url: &str, @@ -93,6 +93,9 @@ async fn main() -> Result<(), Box> { info!("The HTTP server is listening on address '{invehicle_digital_twin_address}'"); // Register the digital twin service with Chariott if Chariott's URL was provided in the config. + // Note: We are not using Chariott's announce, and therefore the digital twin serice will be forcibly unregistered + // after 15 seconds unless the CHARIOTT_REGISTRY_TTL_SECS environment variable is set. Please make sure that + // it is set (and exported) in the shell running Chariott before Chariott has started. if chariott_url_option.is_some() { register_digital_twin_service_with_chariott( &chariott_url_option.unwrap(), diff --git a/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml b/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml new file mode 100644 index 00000000..b83ff773 --- /dev/null +++ b/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml @@ -0,0 +1,11 @@ +# +# In-Vehcile DIgital Twin Service Settings +# + +# The IP address and port number that the in-vehicle digital twin service listens on for digital twin requests. +# Example: "0.0.0.0:80" +invehcile_digital_twin_authority: <> + +# The URL that the Chariott service listens on for requests. +# If you wish to use Chariott, then uncomment this setting. +# chariott_url: <> diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 5797a654..601ca9b7 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::consumer_config::load_settings; +use samples_common::consumer_config; use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; @@ -70,7 +70,7 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); - let settings = load_settings(); + let settings = consumer_config::load_settings(); let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( settings.invehicle_digital_twin_url, diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index ce5f1a1d..c8733746 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; -use samples_common::provider_config::load_settings; +use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; @@ -62,7 +62,7 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let settings = load_settings(); + let settings = provider_config::load_settings(); let provider_authority = settings.provider_authority; diff --git a/samples/common/src/consumer_config.rs b/samples/common/src/consumer_config.rs index fcd34ad9..594f13f4 100644 --- a/samples/common/src/consumer_config.rs +++ b/samples/common/src/consumer_config.rs @@ -7,6 +7,8 @@ use config::{Config, File, FileFormat}; use serde_derive::Deserialize; +const CONFIG_FILENAME: &str = "consumer_settings"; + #[derive(Debug, Deserialize)] pub struct Settings { pub consumer_authority: String, @@ -16,10 +18,8 @@ pub struct Settings { /// Load the settings. pub fn load_settings() -> Settings { - let config = Config::builder() - .add_source(File::new("consumer_settings", FileFormat::Yaml)) - .build() - .unwrap(); + let config = + Config::builder().add_source(File::new(CONFIG_FILENAME, FileFormat::Yaml)).build().unwrap(); let settings: Settings = config.try_deserialize().unwrap(); diff --git a/samples/common/src/misc.rs b/samples/common/src/misc.rs index 10c0ce70..976fde61 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/misc.rs @@ -153,9 +153,10 @@ pub async fn discover_digital_twin_service_using_chariott( return Ok(service.url); } } + Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as none of the services found had the '{constants::chariott::SCHEMA_KIND_FOR_GRPC}' schema kind")) + } else { + Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) } - - Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) } /// Retrieve the In-Vehicle Digital Twin URL. diff --git a/samples/common/src/provider_config.rs b/samples/common/src/provider_config.rs index 86879bf4..a6be4a40 100644 --- a/samples/common/src/provider_config.rs +++ b/samples/common/src/provider_config.rs @@ -7,6 +7,8 @@ use config::{Config, File, FileFormat}; use serde_derive::Deserialize; +const CONFIG_FILENAME: &str = "provider_settings"; + #[derive(Debug, Deserialize)] pub struct Settings { pub provider_authority: String, @@ -16,10 +18,8 @@ pub struct Settings { /// Load the settings. pub fn load_settings() -> Settings { - let config = Config::builder() - .add_source(File::new("provider_settings", FileFormat::Yaml)) - .build() - .unwrap(); + let config = + Config::builder().add_source(File::new(CONFIG_FILENAME, FileFormat::Yaml)).build().unwrap(); let settings: Settings = config.try_deserialize().unwrap(); diff --git a/samples/common/template/consumer_settings.yaml b/samples/common/template/consumer_settings.yaml new file mode 100644 index 00000000..44c0318d --- /dev/null +++ b/samples/common/template/consumer_settings.yaml @@ -0,0 +1,14 @@ +# +# Consumer Settings +# + +# The IP address and port number that the provider listens on for provider requests. +# Example: "0.0.0.0:80" +provider_authority: <> + +# The URL that the in-vehicle digital Twin service listens on for digital twin requests. +invehicle_digital_twin_url: <> + +# The URL that the Chariott service listens on for requests. +# If you wish to use Chariott, then uncomment this setting and comment out the invehicle_digital_twin_url setting. +# chariott_url: <> diff --git a/samples/common/template/provider_settings.yaml b/samples/common/template/provider_settings.yaml new file mode 100644 index 00000000..8f5680a9 --- /dev/null +++ b/samples/common/template/provider_settings.yaml @@ -0,0 +1,14 @@ +# +# Provider Settings +# + +# The IP address and port number that the provider listens on for provider requests. +# Example: "0.0.0.0:80" +provider_authority: <> + +# The URL that the in-vehicle digital Twin service listens on for digital twin requests. +invehicle_digital_twin_url: <> + +# The URL that the Chariott service listens on for requests. +# If you wish to use Chariott, then uncomment this setting and comment out the invehicle_digital_twin_url setting. +# chariott_url: <> diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index b60ce689..fdf70d30 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -9,7 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; -use samples_common::consumer_config::load_settings; +use samples_common::consumer_config; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::{ @@ -136,7 +136,7 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); - let settings = load_settings(); + let settings = consumer_config::load_settings(); let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( settings.invehicle_digital_twin_url, diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 31a01c10..9900e536 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -11,7 +11,7 @@ use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; -use samples_common::provider_config::load_settings; +use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; @@ -214,7 +214,7 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let settings = load_settings(); + let settings = provider_config::load_settings(); let provider_authority = settings.provider_authority; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 9b96369c..b221af8a 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -9,7 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; -use samples_common::consumer_config::load_settings; +use samples_common::consumer_config; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::SubscribeRequest; @@ -45,7 +45,7 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); - let settings = load_settings(); + let settings = consumer_config::load_settings(); let invehicle_digital_twin_url = retrieve_invehicle_digital_twin_url( settings.invehicle_digital_twin_url, diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 70ed13f6..01406e3e 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; -use samples_common::provider_config::load_settings; +use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; @@ -136,7 +136,7 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let settings = load_settings(); + let settings = provider_config::load_settings(); let provider_authority = settings.provider_authority; From 787f4c76e0b4cb694f954e373bb0d229ff3c2749 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 14:36:12 -0700 Subject: [PATCH 15/23] Use Chariott --- README.md | 5 +++++ .../template/invehicle_digital_twin_settings.yaml | 4 ++-- samples/common/template/consumer_settings.yaml | 6 +++--- samples/common/template/provider_settings.yaml | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c2992ade..9faa372c 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,11 @@ Currently, we have no integration tests or end-to-end tests. There are currently three demos: one that demonstrates the use of a property, one that demonstrates the use of a command and one that demonstrates the mixed use of properties and commands. +The demos use config files and we have provided a templated version of each config file. These templates can be found in: + +* {repo-root-dir}/core/invehicle_digital_twin/template +* {repo-root-dir}/samples/common/template + The following instructions are for the demo for the use of a property. Steps: diff --git a/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml b/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml index b83ff773..0a5f50a0 100644 --- a/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml +++ b/core/invehicle-digital-twin/template/invehicle_digital_twin_settings.yaml @@ -1,10 +1,10 @@ # -# In-Vehcile DIgital Twin Service Settings +# In-Vehicle Digital Twin Service Settings # # The IP address and port number that the in-vehicle digital twin service listens on for digital twin requests. # Example: "0.0.0.0:80" -invehcile_digital_twin_authority: <> +invehicle_digital_twin_authority: <> # The URL that the Chariott service listens on for requests. # If you wish to use Chariott, then uncomment this setting. diff --git a/samples/common/template/consumer_settings.yaml b/samples/common/template/consumer_settings.yaml index 44c0318d..175b7640 100644 --- a/samples/common/template/consumer_settings.yaml +++ b/samples/common/template/consumer_settings.yaml @@ -2,11 +2,11 @@ # Consumer Settings # -# The IP address and port number that the provider listens on for provider requests. +# The IP address and port number that the consumer listens on for consumer requests. # Example: "0.0.0.0:80" -provider_authority: <> +consumer_authority: <> -# The URL that the in-vehicle digital Twin service listens on for digital twin requests. +# The URL that the in-vehicle digital twin service listens on for digital twin requests. invehicle_digital_twin_url: <> # The URL that the Chariott service listens on for requests. diff --git a/samples/common/template/provider_settings.yaml b/samples/common/template/provider_settings.yaml index 8f5680a9..99ee05e6 100644 --- a/samples/common/template/provider_settings.yaml +++ b/samples/common/template/provider_settings.yaml @@ -6,7 +6,7 @@ # Example: "0.0.0.0:80" provider_authority: <> -# The URL that the in-vehicle digital Twin service listens on for digital twin requests. +# The URL that the in-vehicle digital twin service listens on for digital twin requests. invehicle_digital_twin_url: <> # The URL that the Chariott service listens on for requests. From ba4b1655f8610f98679d2e1cc6042d447f90b1d6 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:45:49 -0700 Subject: [PATCH 16/23] Use Chariott --- core/invehicle-digital-twin/src/main.rs | 10 ++++---- samples/command/consumer/src/main.rs | 2 +- samples/command/provider/src/main.rs | 3 +-- samples/common/src/lib.rs | 2 +- samples/common/src/{misc.rs => utils.rs} | 29 ++++++++---------------- samples/mixed/consumer/src/main.rs | 2 +- samples/mixed/provider/src/main.rs | 3 +-- samples/property/consumer/src/main.rs | 2 +- samples/property/provider/src/main.rs | 4 +--- 9 files changed, 20 insertions(+), 37 deletions(-) rename samples/common/src/{misc.rs => utils.rs} (90%) diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 5bd8dba3..29d80e4a 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -54,13 +54,11 @@ pub async fn register_digital_twin_service_with_chariott( let request = Request::new(RegisterRequest { service, intents }); - let response = client.register(request).await; - - if response.is_err() { - return Err(Status::internal("Chariott register request failed")); - } + let response = client.register(request) + .await + .map_err(|_| Status::internal("Chariott register request failed"))?; - info!("{:?}", response.unwrap().into_inner()); + info!("{:?}", response.into_inner()); Ok(()) } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 601ca9b7..a7bb9b43 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -9,7 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; use samples_common::consumer_config; -use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url}; +use samples_common::utils::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url}; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::InvokeRequest; diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index c8733746..4e5c650f 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -9,7 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::utils::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; @@ -55,7 +55,6 @@ async fn register_show_notification( } #[tokio::main] -#[allow(clippy::collapsible_else_if)] async fn main() -> Result<(), Box> { // Setup logging. Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 1397f74a..27524aae 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -4,5 +4,5 @@ pub mod constants; pub mod consumer_config; -pub mod misc; pub mod provider_config; +pub mod utils; diff --git a/samples/common/src/misc.rs b/samples/common/src/utils.rs similarity index 90% rename from samples/common/src/misc.rs rename to samples/common/src/utils.rs index 976fde61..abae3e66 100644 --- a/samples/common/src/misc.rs +++ b/samples/common/src/utils.rs @@ -96,26 +96,15 @@ pub async fn discover_digital_twin_provider_using_ibeji( let entity_access_info = response_inner.entity_access_info.expect("Did not find the entity"); - let mut matching_endpoint_info_option: Option = None; - for endpoint_info in entity_access_info.endpoint_info_list { - // We require and endpoint that supports the protocol and supports all of the operations. - if endpoint_info.protocol == protocol - && is_subset(operations, endpoint_info.operations.as_slice()) - { - matching_endpoint_info_option = Some(endpoint_info); - break; - } - } - - if matching_endpoint_info_option.is_none() { - return Err("Did not find an endpoint that met our requirements".to_string()); + match entity_access_info.endpoint_info_list.iter() + .find(|endpoint_info| endpoint_info.protocol == protocol && is_subset(operations, endpoint_info.operations.as_slice())).cloned() + { + Some(result) => { + info!("Found a matching endpoint for entity id {entity_id} that has URI {}", result.uri); + Ok(result) + }, + None => Err("Did not find an endpoint that met our requirements".to_string()) } - - let result = matching_endpoint_info_option.unwrap(); - - info!("Found a matching endpoint for entity id {entity_id} that has URI {}", result.uri); - - Ok(result) } /// Use Chariott to discover the endpoint for the digital twin service. @@ -194,7 +183,7 @@ pub async fn retrieve_invehicle_digital_twin_url( } #[cfg(test)] -mod ibeji_common_misc_tests { +mod ibeji_common_utils_tests { use super::*; #[test] diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index fdf70d30..e4c182b5 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::utils::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::consumer_config; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 9900e536..b56ab512 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -10,7 +10,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::utils::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; @@ -207,7 +207,6 @@ async fn start_vehicle_simulator( } #[tokio::main] -// #[allow(clippy::collapsible_else_if)] async fn main() -> Result<(), Box> { // Setup logging. Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index b221af8a..96bc94b5 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -8,7 +8,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::utils::{discover_digital_twin_provider_using_ibeji, retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::consumer_config; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_protobuf_data_access::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 01406e3e..3cf84c6f 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -9,7 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_common::constants::{digital_twin_operation, digital_twin_protocol}; -use samples_common::misc::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; +use samples_common::utils::{retrieve_invehicle_digital_twin_url, retry_async_based_on_status}; use samples_common::provider_config; use samples_protobuf_data_access::digital_twin::v1::digital_twin_client::DigitalTwinClient; use samples_protobuf_data_access::digital_twin::v1::{EndpointInfo, EntityAccessInfo, RegisterRequest}; @@ -64,7 +64,6 @@ async fn register_ambient_air_temperature( /// /// # Arguments /// `id_to_subscribers_map` - The id to subscribers map. -#[allow(clippy::collapsible_else_if)] fn start_ambient_air_temperature_data_stream(subscription_map: Arc>) { debug!("Starting the Provider's ambient air temperature data stream."); tokio::spawn(async move { @@ -129,7 +128,6 @@ fn start_ambient_air_temperature_data_stream(subscription_map: Arc Result<(), Box> { // Setup logging. Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); From f247de0e11dbb481e7aeaf9fcf054a3e0a2f5c0d Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 16:31:28 -0700 Subject: [PATCH 17/23] Use Chariott --- README.md | 4 ++-- samples/common/src/utils.rs | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9faa372c..fe124b6d 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,8 @@ demonstrates the mixed use of properties and commands. The demos use config files and we have provided a templated version of each config file. These templates can be found in: -* {repo-root-dir}/core/invehicle_digital_twin/template -* {repo-root-dir}/samples/common/template +- {repo-root-dir}/core/invehicle_digital_twin/template +- {repo-root-dir}/samples/common/template The following instructions are for the demo for the use of a property. diff --git a/samples/common/src/utils.rs b/samples/common/src/utils.rs index abae3e66..fd553012 100644 --- a/samples/common/src/utils.rs +++ b/samples/common/src/utils.rs @@ -124,7 +124,7 @@ pub async fn discover_digital_twin_service_using_chariott( }); // Get list of services at the requested namespace, if any. - let services: Option> = client + let fulfillment_result: Option> = client .fulfill(request) .await? .into_inner() @@ -136,15 +136,13 @@ pub async fn discover_digital_twin_service_using_chariott( }); // If we discovered one or more service, then return the URL for the first one that uses gRPC. - if services.is_some() { - for service in services.unwrap() { - if service.schema_kind == constants::chariott::SCHEMA_KIND_FOR_GRPC { - return Ok(service.url); - } - } - Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as none of the services found had the '{constants::chariott::SCHEMA_KIND_FOR_GRPC}' schema kind")) - } else { - Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) + match fulfillment_result { + Some(services) => + services.iter() + .find(|service| service.schema_kind == constants::chariott::SCHEMA_KIND_FOR_GRPC) + .map(|service| service.url.clone()) + .ok_or(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as none of the services found had the '{constants::chariott::SCHEMA_KIND_FOR_GRPC}' schema kind")), + None => Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) } } From 19a9b7bfdad81af1415726bd366f5498cd918367 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 16:40:38 -0700 Subject: [PATCH 18/23] Use Chariott --- samples/common/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/common/src/utils.rs b/samples/common/src/utils.rs index fd553012..80945f12 100644 --- a/samples/common/src/utils.rs +++ b/samples/common/src/utils.rs @@ -137,7 +137,7 @@ pub async fn discover_digital_twin_service_using_chariott( // If we discovered one or more service, then return the URL for the first one that uses gRPC. match fulfillment_result { - Some(services) => + Some(services) => services.iter() .find(|service| service.schema_kind == constants::chariott::SCHEMA_KIND_FOR_GRPC) .map(|service| service.url.clone()) From edf6f637a21dbd7b8d02f1b04bdb1c48d3d06586 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:11:11 -0700 Subject: [PATCH 19/23] Use Chariott --- core/invehicle-digital-twin/src/digitaltwin_impl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/invehicle-digital-twin/src/digitaltwin_impl.rs b/core/invehicle-digital-twin/src/digitaltwin_impl.rs index 69a9cc61..28187209 100644 --- a/core/invehicle-digital-twin/src/digitaltwin_impl.rs +++ b/core/invehicle-digital-twin/src/digitaltwin_impl.rs @@ -86,7 +86,7 @@ impl DigitalTwinImpl { /// * `entity` - The entity. fn register_entity(&self, entity_access_info: EntityAccessInfo) -> Result<(), Status> { // This block controls the lifetime of the lock. - { + // { let mut lock: RwLockWriteGuard> = self.entity_access_info_map.write(); match lock.get(&entity_access_info.id) { @@ -97,7 +97,7 @@ impl DigitalTwinImpl { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } }; - } + // } debug!("Registered entity {}", &entity_access_info.id); From 022ac13b39818a44584542443fe834a7a9b1fdbb Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:19:50 -0700 Subject: [PATCH 20/23] Use Chariott --- core/invehicle-digital-twin/src/digitaltwin_impl.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/invehicle-digital-twin/src/digitaltwin_impl.rs b/core/invehicle-digital-twin/src/digitaltwin_impl.rs index 28187209..26315ec7 100644 --- a/core/invehicle-digital-twin/src/digitaltwin_impl.rs +++ b/core/invehicle-digital-twin/src/digitaltwin_impl.rs @@ -86,10 +86,11 @@ impl DigitalTwinImpl { /// * `entity` - The entity. fn register_entity(&self, entity_access_info: EntityAccessInfo) -> Result<(), Status> { // This block controls the lifetime of the lock. - // { + { let mut lock: RwLockWriteGuard> = self.entity_access_info_map.write(); - match lock.get(&entity_access_info.id) { + let get_result = lock.get(&entity_access_info.id); + match get_result { Some(_) => { return Err(Status::unimplemented("The in-vehicle digital twin service does not yet support multiple registrations of the same entity.")); } @@ -97,7 +98,7 @@ impl DigitalTwinImpl { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } }; - // } + } debug!("Registered entity {}", &entity_access_info.id); From 27ce54cc23b421ad4e9f9b839560611c08122e2b Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:27:41 -0700 Subject: [PATCH 21/23] Use Chariott --- samples/common/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/common/src/utils.rs b/samples/common/src/utils.rs index 80945f12..be3c6e33 100644 --- a/samples/common/src/utils.rs +++ b/samples/common/src/utils.rs @@ -141,7 +141,7 @@ pub async fn discover_digital_twin_service_using_chariott( services.iter() .find(|service| service.schema_kind == constants::chariott::SCHEMA_KIND_FOR_GRPC) .map(|service| service.url.clone()) - .ok_or(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as none of the services found had the '{constants::chariott::SCHEMA_KIND_FOR_GRPC}' schema kind")), + .ok_or_else(|| Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as none of the services found had the '{constants::chariott::SCHEMA_KIND_FOR_GRPC}' schema kind")), None => Err(Status::not_found("Failed to discover the in-vehicle digital twin service's URL, as it is not registered with Chariott")) } } From 8074b81cea608d56671c2698862e6fa870afbf81 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:35:31 -0700 Subject: [PATCH 22/23] Use Chariott --- samples/property/provider/src/main.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 3cf84c6f..f02c74cc 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -113,13 +113,11 @@ fn start_ambient_air_temperature_data_stream(subscription_map: Arc Date: Mon, 5 Jun 2023 21:38:27 -0700 Subject: [PATCH 23/23] Use Chariott --- core/invehicle-digital-twin/src/main.rs | 3 ++- samples/common/src/utils.rs | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/invehicle-digital-twin/src/main.rs b/core/invehicle-digital-twin/src/main.rs index 29d80e4a..b90ae9ae 100644 --- a/core/invehicle-digital-twin/src/main.rs +++ b/core/invehicle-digital-twin/src/main.rs @@ -54,7 +54,8 @@ pub async fn register_digital_twin_service_with_chariott( let request = Request::new(RegisterRequest { service, intents }); - let response = client.register(request) + let response = client + .register(request) .await .map_err(|_| Status::internal("Chariott register request failed"))?; diff --git a/samples/common/src/utils.rs b/samples/common/src/utils.rs index be3c6e33..46c2822c 100644 --- a/samples/common/src/utils.rs +++ b/samples/common/src/utils.rs @@ -96,14 +96,23 @@ pub async fn discover_digital_twin_provider_using_ibeji( let entity_access_info = response_inner.entity_access_info.expect("Did not find the entity"); - match entity_access_info.endpoint_info_list.iter() - .find(|endpoint_info| endpoint_info.protocol == protocol && is_subset(operations, endpoint_info.operations.as_slice())).cloned() + match entity_access_info + .endpoint_info_list + .iter() + .find(|endpoint_info| { + endpoint_info.protocol == protocol + && is_subset(operations, endpoint_info.operations.as_slice()) + }) + .cloned() { Some(result) => { - info!("Found a matching endpoint for entity id {entity_id} that has URI {}", result.uri); + info!( + "Found a matching endpoint for entity id {entity_id} that has URI {}", + result.uri + ); Ok(result) - }, - None => Err("Did not find an endpoint that met our requirements".to_string()) + } + None => Err("Did not find an endpoint that met our requirements".to_string()), } }