From 80e0924571ebdbbff3344d0634d8714506d93d72 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 1 May 2023 09:39:23 -0700 Subject: [PATCH 01/41] Make protocol agnostic --- Cargo.toml | 18 +- common-test/src/lib.rs | 4 +- common/src/lib.rs | 4 +- data-exchange/Cargo.toml | 12 + data-exchange/src/lib.rs | 50 ++++ dt-model/dt-model-identifiers/src/sdv_v1.rs | 6 - dt-model/dtdl/v2/content/sdv/vehicle.json | 60 ++++ dtdl-parser/src/model_parser.rs | 61 ++--- .../samples/remotely_accessible_resource.json | 22 -- dtdl/v2/context/SDV.v2.context.json | 13 - in-vehicle-digital-twin/Cargo.toml | 1 + .../src/digitaltwin_impl.rs | 259 ++++++++++-------- in-vehicle-digital-twin/src/main.rs | 4 - in-vehicle-digital-twin/src/provider_impl.rs | 76 ----- proto/Cargo.toml | 2 +- proto/build.rs | 2 - proto/digitaltwin.proto | 10 +- proto/src/lib.rs | 13 - samples/command/consumer/Cargo.toml | 3 +- samples/command/consumer/src/consumer_impl.rs | 6 +- samples/command/consumer/src/main.rs | 75 ++--- .../dtdl/content/show_notification.json | 3 + samples/command/provider/Cargo.toml | 2 + samples/command/provider/src/main.rs | 45 ++- samples/command/provider/src/provider_impl.rs | 11 +- samples/mixed/consumer/Cargo.toml | 3 +- samples/mixed/consumer/src/consumer_impl.rs | 6 +- samples/mixed/consumer/src/main.rs | 14 +- samples/mixed/dtdl/content/mixed.json | 12 + samples/mixed/provider/Cargo.toml | 2 + samples/mixed/provider/src/main.rs | 10 +- samples/mixed/provider/src/provider_impl.rs | 12 +- samples/property/consumer/Cargo.toml | 3 +- .../property/consumer/src/consumer_impl.rs | 6 +- samples/property/consumer/src/main.rs | 10 +- .../dtdl/content/ambient_air_temperature.json | 3 + samples/property/provider/Cargo.toml | 2 + samples/property/provider/src/main.rs | 10 +- .../property/provider/src/provider_impl.rs | 6 +- samples/proto/Cargo.toml | 17 ++ samples/proto/build.rs | 9 + .../v1/digital_twin_consumer.proto | 4 +- .../v1/digital_twin_provider.proto | 4 +- samples/proto/src/lib.rs | 17 ++ 44 files changed, 495 insertions(+), 417 deletions(-) create mode 100644 data-exchange/Cargo.toml create mode 100644 data-exchange/src/lib.rs create mode 100644 dt-model/dtdl/v2/content/sdv/vehicle.json delete mode 100644 dtdl/samples/remotely_accessible_resource.json delete mode 100644 dtdl/v2/context/SDV.v2.context.json delete mode 100644 in-vehicle-digital-twin/src/provider_impl.rs create mode 100644 samples/proto/Cargo.toml create mode 100644 samples/proto/build.rs rename proto/consumer.proto => samples/proto/sample_grpc/v1/digital_twin_consumer.proto (88%) rename proto/provider.proto => samples/proto/sample_grpc/v1/digital_twin_provider.proto (94%) create mode 100644 samples/proto/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 0359525e..960cef63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,16 @@ members = [ "common", "common-test", "dt-model/dt-model-identifiers", - "proto", + "data-exchange", "dtdl-parser", "in-vehicle-digital-twin", + "samples/proto", "samples/command/consumer", "samples/command/provider", - "samples/mixed/consumer", - "samples/mixed/provider", - "samples/property/consumer", - "samples/property/provider" +# "samples/mixed/consumer", +# "samples/mixed/provider", +# "samples/property/consumer", +# "samples/property/provider" ] [workspace.dependencies] @@ -29,10 +30,11 @@ lazy_static = "1.4.0" log = "^0.4" parking_lot = "0.12.1" prost = "0.11" -regex = " 1.7.1" +regex = " 1.8.1" tokio = "1.0" -tonic = "0.8.2" -tonic-build = "0.8.2" +tonic = "0.9.2" +tonic-build = "0.9.2" +serde = "1.0.160" serde_json = "^1.0" strum = "0.24" strum_macros = "0.24" diff --git a/common-test/src/lib.rs b/common-test/src/lib.rs index 68ff6247..496efcbd 100644 --- a/common-test/src/lib.rs +++ b/common-test/src/lib.rs @@ -34,7 +34,7 @@ pub fn set_dtdl_path() { let repo_dir_result = get_repo_dir(); if let Some(repo_dir) = repo_dir_result { let value = format!( - "{repo_dir}/opendigitaltwins-dtdl/DTDL;{repo_dir}/iot-plugandplay-models;{repo_dir}/dtdl" + "{repo_dir}/opendigitaltwins-dtdl/DTDL;{repo_dir}/iot-plugandplay-models;{repo_dir}/dtdl;{repo_dir}/dt-model/dtdl" ); env::set_var(DTDL_PATH, &value); trace!("{DTDL_PATH}={value}"); @@ -56,7 +56,7 @@ mod ibeji_common_test_tests { assert!(get_dtdl_path_result.is_ok()); let dtdl_path = get_dtdl_path_result.unwrap(); assert!(!dtdl_path.is_empty()); - assert!(dtdl_path.contains("/opendigitaltwins-dtdl/DTDL;")); + assert!(dtdl_path.contains("/opendigitaltwins-dtdl/DTDL")); assert!(dtdl_path.contains("/dtdl")); } } diff --git a/common/src/lib.rs b/common/src/lib.rs index 046a5212..1e55194f 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -56,9 +56,9 @@ mod ibeji_common_tests { fn find_full_path_test() { set_dtdl_path(); - let find_full_path_result = find_full_path("samples/remotely_accessible_resource.json"); + let find_full_path_result = find_full_path("v2/content/sdv/vehicle.json"); assert!(find_full_path_result.is_ok()); let full_path = find_full_path_result.unwrap(); - assert!(full_path.ends_with("/samples/remotely_accessible_resource.json")); + assert!(full_path.ends_with("/v2/content/sdv/vehicle.json")); } } diff --git a/data-exchange/Cargo.toml b/data-exchange/Cargo.toml new file mode 100644 index 00000000..a87063bb --- /dev/null +++ b/data-exchange/Cargo.toml @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +[package] +name = "data-exchange" +version = "0.1.0" +edition = "2021" +license = "MIT" + +[dependencies] +serde = { workspace = true, features = ["derive"] } diff --git a/data-exchange/src/lib.rs b/data-exchange/src/lib.rs new file mode 100644 index 00000000..c7b97823 --- /dev/null +++ b/data-exchange/src/lib.rs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +pub mod digitaltwin { + use serde::{Deserialize, Serialize}; + + #[derive(Deserialize, Serialize, Debug, Clone)] + pub struct Endpoint { + pub protocol: String, + pub operations: Vec, + pub uri: String, + pub context: String, + } + + #[derive(Deserialize, Serialize, Debug, Clone)] + pub struct Entity { + pub name: String, + pub id: String, + pub description: String, + pub endpoints: Vec, + } + + #[derive(Deserialize, Serialize)] + pub struct FindByIdRequestPayload { + pub id: String, + } + + #[derive(Deserialize, Serialize)] + pub struct FindByIdResponsePayload { + pub entity: Option + } + + #[derive(Deserialize, Serialize)] + pub struct RegisterRequestPayload { + pub entities: Vec, + } + + #[derive(Deserialize, Serialize)] + pub struct RegisterResponsePayload { + } + + #[derive(Deserialize, Serialize)] + pub struct UnregisterRequestPayload { + } + + #[derive(Deserialize, Serialize)] + pub struct UnregisterResponsePayload { + } +} diff --git a/dt-model/dt-model-identifiers/src/sdv_v1.rs b/dt-model/dt-model-identifiers/src/sdv_v1.rs index 83b42d55..4cd1879a 100644 --- a/dt-model/dt-model-identifiers/src/sdv_v1.rs +++ b/dt-model/dt-model-identifiers/src/sdv_v1.rs @@ -29,9 +29,3 @@ pub mod vehicle { } } } - -pub mod property { - pub mod uri { - pub const ID: &str = "dtmi:sdv:property:uri;1"; - } -} diff --git a/dt-model/dtdl/v2/content/sdv/vehicle.json b/dt-model/dtdl/v2/content/sdv/vehicle.json new file mode 100644 index 00000000..adbe2685 --- /dev/null +++ b/dt-model/dtdl/v2/content/sdv/vehicle.json @@ -0,0 +1,60 @@ +[ + { + "@context": ["dtmi:dtdl:context;2"], + "@type": "Interface", + "@id": "dtmi:sdv:Vehicle:Cabin:HVAC;1", + "description": "Heat, Ventilation and Air Conditioning", + "contents": [ + { + "@type": ["Property", "Temperature"], + "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1", + "name": "AmbientAirTemperature", + "description": "The immediate surroundings air temperature (in Fahrenheit).", + "schema": "integer", + "unit": "degreeFahrenheit" + }, + { + "@type": ["Property"], + "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:IsAirConditioningActive;1", + "name": "IsAirConditioningActive", + "description": "Is air conditioning active?", + "schema": "boolean" + } + ] + }, + { + "@context": ["dtmi:dtdl:context;2"], + "@type": "Interface", + "@id": "dtmi:sdv:Vehicle:OBD;1", + "description": "On-board Diagnostics Interface", + "contents": [ + { + "@type": ["Property"], + "@id": "dtmi:sdv:Vehicle:OBD:HybridBatteryRemaining;1", + "name": "HybridBatteryRemaining", + "description": "The remaining hybrid battery life.", + "schema": "integer", + "unit": "percent" + } + ] + }, + { + "@context": ["dtmi:dtdl:context;2"], + "@type": "Interface", + "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI;1", + "description": "The Human Machine Interface.", + "contents": [ + { + "@type": ["Command"], + "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI:ShowNotification;1", + "name": "ShowNotification", + "request": { + "name": "ShowNotification", + "displayName": "Show Notification", + "descriptiption": "Show a notification on the HMI.", + "schema": "string" + } + } + ] + } +] \ No newline at end of file diff --git a/dtdl-parser/src/model_parser.rs b/dtdl-parser/src/model_parser.rs index e0311a3b..e92f76fb 100644 --- a/dtdl-parser/src/model_parser.rs +++ b/dtdl-parser/src/model_parser.rs @@ -256,12 +256,6 @@ impl ModelParser { let dtdl_2_context_value = self.retrieve_context(dtdl_2_context_path)?; self.replace_context_inline_in_doc(doc, "dtmi:dtdl:context;2", &dtdl_2_context_value)?; - let sdv_2_context_path_string = find_full_path("v2/context/SDV.v2.context.json")?; - let sdv_2_context_path_string_unwrapped = sdv_2_context_path_string; - let sdv_2_context_path = Path::new(&sdv_2_context_path_string_unwrapped); - let sdv_2_context_value = self.retrieve_context(sdv_2_context_path)?; - self.replace_context_inline_in_doc(doc, "dtmi:sdv:context;2", &sdv_2_context_value)?; - Ok(()) } @@ -1101,16 +1095,16 @@ mod model_parser_tests { #[rustfmt::skip] #[test] - fn demo_validation_test() { + fn sdv_vehicle_validation_test() { set_dtdl_path(); let mut json_texts = Vec::::new(); - let demo_path_result = find_full_path("samples/demo_resources.json"); - assert!(demo_path_result.is_ok()); - let demo_contents_result = retrieve_dtdl(&demo_path_result.unwrap()); - assert!(demo_contents_result.is_ok()); - json_texts.push(demo_contents_result.unwrap()); + let vehicle_path_result = find_full_path("v2/content/sdv/vehicle.json"); + assert!(vehicle_path_result.is_ok()); + let vehicle_contents_result = retrieve_dtdl(&vehicle_path_result.unwrap()); + assert!(vehicle_contents_result.is_ok()); + json_texts.push(vehicle_contents_result.unwrap()); let mut parser = ModelParser::new(); let model_dict_result = parser.parse(&json_texts); @@ -1120,39 +1114,26 @@ mod model_parser_tests { model_dict_result.err().unwrap() ); let model_dict = model_dict_result.unwrap(); - assert!( - model_dict.len() == 13, - "expected length was 13, actual length is {}", - model_dict.len() - ); let ambient_air_temperature_id: Option = create_dtmi("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"); assert!(ambient_air_temperature_id.is_some()); let ambient_air_temperature_entity_result = model_dict.get(&ambient_air_temperature_id.unwrap()); assert!(ambient_air_temperature_entity_result.is_some()); - let ambient_air_temperature_uri_property_result = ambient_air_temperature_entity_result - .unwrap() - .undefined_properties() - .get("dtmi:sdv:property:uri;1"); - assert!(ambient_air_temperature_uri_property_result.is_some()); - let ambient_air_temperature_uri_property_value_result = - ambient_air_temperature_uri_property_result.unwrap().get("@value"); - assert!(ambient_air_temperature_uri_property_value_result.is_some()); - assert!(ambient_air_temperature_uri_property_value_result.unwrap() == "http://[::1]:40010"); // Devskim: ignore DS137138 - - let send_notification_id: Option = create_dtmi("dtmi:sdv:Vehicle:Cabin:HVAC:SendNotification;1"); - assert!(send_notification_id.is_some()); - let send_notification_entity_result = model_dict.get(&send_notification_id.unwrap()); - assert!(send_notification_entity_result.is_some()); - let send_notification_uri_property_result = send_notification_entity_result - .unwrap() - .undefined_properties() - .get("dtmi:sdv:property:uri;1"); - assert!(send_notification_uri_property_result.is_some()); - let send_notification_uri_property_value_result = - send_notification_uri_property_result.unwrap().get("@value"); - assert!(send_notification_uri_property_value_result.is_some()); - assert!(send_notification_uri_property_value_result.unwrap() == "http://[::1]:40010"); // Devskim: ignore DS137138 + + let is_air_conditioning_active_id: Option = create_dtmi("dtmi:sdv:Vehicle:Cabin:HVAC:IsAirConditioningActive;1"); + assert!(is_air_conditioning_active_id.is_some()); + let is_air_conditioning_active_entity_result = model_dict.get(&is_air_conditioning_active_id.unwrap()); + assert!(is_air_conditioning_active_entity_result.is_some()); + + let hybrid_battery_remaining_id: Option = create_dtmi("dtmi:sdv:Vehicle:OBD:HybridBatteryRemaining;1"); + assert!(hybrid_battery_remaining_id.is_some()); + let hybrid_battery_remaining_entity_result = model_dict.get(&hybrid_battery_remaining_id.unwrap()); + assert!(hybrid_battery_remaining_entity_result.is_some()); + + let show_notification_id: Option = create_dtmi("dtmi:sdv:Vehicle:Cabin:Infotainment:HMI:ShowNotification;1"); + assert!(show_notification_id.is_some()); + let show_notification_entity_result = model_dict.get(&show_notification_id.unwrap()); + assert!(show_notification_entity_result.is_some()); } } diff --git a/dtdl/samples/remotely_accessible_resource.json b/dtdl/samples/remotely_accessible_resource.json deleted file mode 100644 index e7563183..00000000 --- a/dtdl/samples/remotely_accessible_resource.json +++ /dev/null @@ -1,22 +0,0 @@ - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:Cabin:HAVC;1", - "contents": [ - { - "@type": ["Property", "Temperature", "RemotelyAccessible"], - "name": "Cabin_AmbientAirTemperature", - "@id": "dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1", - "description": "The immediate surroundings air temperature (in Fahrenheit).", - "schema": "double", - "unit": "degreeFahrenheit", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "operations": [ "Get", "Set", "Subscribe", "Unsubscribe" ] - } - ] - } - ] - } diff --git a/dtdl/v2/context/SDV.v2.context.json b/dtdl/v2/context/SDV.v2.context.json deleted file mode 100644 index 22a06907..00000000 --- a/dtdl/v2/context/SDV.v2.context.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "remote_access": { - "@id": "dtmi:sdv:property:remote_access;1", - "@type": "@vocab" - }, - "uri": { - "@id": "dtmi:sdv:property:uri;1" - }, - "operations": { - "@id": "dtmi:sdv:property:operations;1", - "@type": "@vocab" - } -} diff --git a/in-vehicle-digital-twin/Cargo.toml b/in-vehicle-digital-twin/Cargo.toml index 514079f2..83ed7120 100644 --- a/in-vehicle-digital-twin/Cargo.toml +++ b/in-vehicle-digital-twin/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } +data-exchange = { path = "../data-exchange" } env_logger= { workspace = true } ibeji-common = { path = "../common" } ibeji-common_test = { path = "../common-test" } diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index bb325254..05008f89 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -4,23 +4,21 @@ extern crate iref; -use dtdl_parser::model_parser::ModelParser; use log::Level::Debug; use log::{debug, info, log_enabled, warn}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use proto::digitaltwin::digital_twin_server::DigitalTwin; use proto::digitaltwin::{ FindByIdRequest, FindByIdResponse, RegisterRequest, RegisterResponse, UnregisterRequest, - UnregisterResponse, -}; -use serde_json::Value; + UnregisterResponse}; +use data_exchange::digitaltwin::{Entity, FindByIdRequestPayload, FindByIdResponsePayload, RegisterRequestPayload}; use std::collections::HashMap; use std::sync::Arc; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct DigitalTwinImpl { - pub entity_map: Arc>>, + pub entity_map: Arc>>, } #[tonic::async_trait] @@ -34,36 +32,44 @@ impl DigitalTwin for DigitalTwinImpl { request: Request, ) -> Result, Status> { let request_inner = request.into_inner(); - let entity_id = request_inner.entity_id; + + let payload: FindByIdRequestPayload = match serde_json::from_str(&request_inner.payload) { + Ok(content) => content, + Err(error) => { + return Err(Status::internal(format!( + "Unexpected error with the payload: {error:?}" + ))) + } + }; + + let entity_id = payload.id; info!("Received a find_by_id request for entity id {entity_id}"); - let dtdl; + let entity: Option; // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = self.entity_map.read(); - let val_option = lock.get(&entity_id); - let val = match val_option { - Some(v) => v, - None => { - return Err(Status::not_found(format!( - "Unable to find the DTDL for entity id {entity_id}" - ))) - } - }; - - dtdl = match serde_json::to_string_pretty(&val) { - Ok(content) => content, - Err(error) => { - return Err(Status::internal(format!( - "Unexpected error with the DTDL for entity id {entity_id}: {error:?}" - ))) - } - }; + let lock: RwLockReadGuard> = self.entity_map.read(); + entity = lock.get(&entity_id).map(|value| value.clone()); } - let response = FindByIdResponse { dtdl }; + let response_payload = FindByIdResponsePayload { + entity + }; + + let payload = match serde_json::to_string(&response_payload) { + Ok(content) => content, + Err(error) => { + return Err(Status::internal(format!( + "Unexpected error with the conversion to JSON for entity {entity_id}: {error}" + ))) + } + }; + + info!("{}", payload); + + let response = FindByIdResponse { payload }; debug!("Responded to the find_by_id request."); @@ -79,16 +85,28 @@ impl DigitalTwin for DigitalTwinImpl { request: Request, ) -> Result, Status> { let request_inner = request.into_inner(); - let dtdl = request_inner.dtdl; - info!("Received a register request for the DTDL:\n{}", &dtdl); + let payload: RegisterRequestPayload = match serde_json::from_str(&request_inner.payload) { + Ok(content) => content, + Err(error) => { + return Err(Status::internal(format!( + "Unexpected error with the payload: {error:?}" + ))) + } + }; + + for entity in &payload.entities { + info!("Received a register request for the the entity:\n{}", &entity.id); - let register_each_one_result = self.register_each_one(&dtdl); - if let Err(error) = register_each_one_result { - return Err(Status::internal(error)); + match self.register_entity(entity.clone()) { + Ok(_) => { + self.register_entity(entity.clone()).map_err(|error| return Status::internal(format!("{}", error)))? + }, + Err(error) => return Err(Status::internal(error)) + }; } - let response = RegisterResponse {}; + let response = RegisterResponse {payload: String::from("")}; debug!("Completed the register request."); @@ -110,62 +128,27 @@ impl DigitalTwin for DigitalTwinImpl { } impl DigitalTwinImpl { - /// This function assumes that an array of resources has been provided and that each resource in the array needs to be registered. - /// - /// # Arguments - /// * `dtdl` - The DTDL for the array. - #[allow(unused_variables)] - fn register_each_one(&self, dtdl: &str) -> Result<(), String> { - let doc: Value = match serde_json::from_str(dtdl) { - Ok(json) => json, - Err(error) => return Err(format!("Failed to parse the DTDL due to: {error:?}")), - }; - - match doc { - Value::Array(array) => { - for v in array.iter() { - self.register_one(v)? - } - } - _ => return Err(String::from("An unexpected item was encountered in the DTDL.")), - }; - - Ok(()) - } - /// Register the resource specified in the the JSON doc. + /// Register the entity. /// /// # Arguments - /// * `doc` - The JSON doc that specifies the entity. - fn register_one(&self, doc: &Value) -> Result<(), String> { - let dtdl = match serde_json::to_string_pretty(&doc) { - Ok(content) => content, - Err(error) => { - return Err(format!("Failed to make the DTDL pretty due to: : {error:?}")) - } - }; - - let mut parser = ModelParser::new(); - let json_texts = vec![dtdl]; - - let model_dict_result = parser.parse(&json_texts); - if let Err(error) = model_dict_result { - return Err(format!("Failed to parse the DTDL due to: {error:?}")); - } - let model_dict = model_dict_result.unwrap(); - + /// * `entity` - The entity. + fn register_entity(&self, entity: Entity) -> Result<(), String> { // This block controls the lifetime of the lock. { - let mut lock: RwLockWriteGuard> = self.entity_map.write(); - for id in model_dict.keys() { - lock.insert(id.to_string(), doc.clone()); - } + let mut lock: RwLockWriteGuard> = self.entity_map.write(); + match lock.get(&entity.id) { + Some(_) => { + // TODO: merge existing contents with new contents + }, + None => { + lock.insert(entity.id.clone(), entity.clone()); + } + }; } if log_enabled!(Debug) { - for id in model_dict.keys() { - debug!("Registered DTDL for id {id}"); - } + debug!("Registered entity {}", &entity.id); } Ok(()) @@ -175,37 +158,34 @@ impl DigitalTwinImpl { #[cfg(test)] mod digitaltwin_impl_tests { use super::*; - use ibeji_common::find_full_path; use ibeji_common_test::set_dtdl_path; - use std::fs; - use std::path::Path; - - fn retrieve_dtdl(file_path: &str) -> Result { - let path = Path::new(file_path); - let read_result = fs::read_to_string(path); - match read_result { - Ok(contents) => Ok(contents), - Err(error) => Err(format!("Unable to retrieve the DTDL due to: {error:?}")), - } - } + use data_exchange::digitaltwin::{Endpoint, FindByIdResponsePayload}; #[tokio::test] async fn find_by_id_test() { set_dtdl_path(); - // Note: We can use any valid JSON. We'll use samples/remotely_accessible_resource.json. - let dtdl_path_result = find_full_path("samples/remotely_accessible_resource.json"); - assert!(dtdl_path_result.is_ok()); - let dtdl_path = dtdl_path_result.unwrap(); - let dtdl_result = retrieve_dtdl(&dtdl_path); - assert!(dtdl_result.is_ok()); - let dtdl = dtdl_result.unwrap(); + let mut operations = Vec::new(); + operations.push(String::from("Subscribe")); + operations.push(String::from("Unsubscribe")); + + let endpoint = Endpoint { + protocol: String::from("grpc"), + uri: String::from("http://[::1]:40010"), + context: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + operations, + }; - let dtdl_json_result = serde_json::from_str(&dtdl); - assert!(dtdl_json_result.is_ok()); - let dtdl_json = dtdl_json_result.unwrap(); + let mut endpoints = Vec::new(); + endpoints.push(endpoint); - let entity_id = String::from("dtmi::some_id"); + let entity = Entity { + digital_twin_model: String::from("dtmi:svd:vehcile;1"), + name: String::from("AmbientAirTemperature"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + description: String::from("Ambient air temperature"), + endpoints + }; let entity_map = Arc::new(RwLock::new(HashMap::new())); @@ -213,41 +193,84 @@ mod digitaltwin_impl_tests { // This block controls the lifetime of the lock. { - let mut lock: RwLockWriteGuard> = entity_map.write(); - lock.insert(entity_id.clone(), dtdl_json); + let mut lock: RwLockWriteGuard> = entity_map.write(); + lock.insert(entity.id.clone(), entity.clone()); } - let request = tonic::Request::new(FindByIdRequest { entity_id }); + let request_payload = FindByIdRequestPayload { + id: entity.id.clone() + }; + + let request_payload_result = serde_json::to_string(&request_payload); + assert!(request_payload_result.is_ok()); + + let request = tonic::Request::new(FindByIdRequest { payload: request_payload_result.unwrap()}); let result = digital_twin_impl.find_by_id(request).await; assert!(result.is_ok()); let response = result.unwrap(); - let dtdl = response.into_inner().dtdl; - assert!(!dtdl.is_empty()); + let response_inner = response.into_inner(); + + let response_payload_result: Result = serde_json::from_str(&response_inner.payload); + assert!(response_payload_result.is_ok()); + + // assert!(!response_payload.entity.is_empty()); } #[tokio::test] async fn register_test() { set_dtdl_path(); + let mut operations = Vec::new(); + operations.push(String::from("Subscribe")); + operations.push(String::from("Unsubscribe")); + + let endpoint = Endpoint { + protocol: String::from("grpc"), + uri: String::from("http://[::1]:40010"), + context: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + operations, + }; + + let mut endpoints = Vec::new(); + endpoints.push(endpoint); + + let entity = Entity { + digital_twin_model: String::from("dtmi:svd:vehcile;1"), + name: String::from("AmbientAirTemperature"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + description: String::from("Ambient air temperature"), + endpoints + }; + + let mut entities = Vec::new(); + entities.push(entity.clone()); + let entity_map = Arc::new(RwLock::new(HashMap::new())); + let digital_twin_impl = DigitalTwinImpl { entity_map: entity_map.clone() }; - let dtdl_path_result = find_full_path("samples/demo_resources.json"); - assert!(dtdl_path_result.is_ok()); - let dtdl_path = dtdl_path_result.unwrap(); - let dtdl_result = retrieve_dtdl(&dtdl_path); - assert!(dtdl_result.is_ok()); - let dtdl = dtdl_result.unwrap(); + // This block controls the lifetime of the lock. + { + let mut lock: RwLockWriteGuard> = entity_map.write(); + lock.insert(entity.id.clone(), entity.clone()); + } + + let register_request_payload = RegisterRequestPayload { + entities: entities.clone() + }; + + let request_payload_result = serde_json::to_string(®ister_request_payload); + assert!(request_payload_result.is_ok()); - let request = tonic::Request::new(RegisterRequest { dtdl }); + let request = tonic::Request::new(RegisterRequest { payload: request_payload_result.unwrap() }); let result = digital_twin_impl.register(request).await; assert!(result.is_ok()); // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = entity_map.read(); + let lock: RwLockReadGuard> = entity_map.read(); // Make sure that we populated the entity map from the contents of the DTDL. - assert!(lock.len() == 13, "expected length was 13, actual length is {}", lock.len()); + assert!(lock.len() == 1, "expected length was 1, actual length is {}", lock.len()); } } } diff --git a/in-vehicle-digital-twin/src/main.rs b/in-vehicle-digital-twin/src/main.rs index 30f37b66..d4d32715 100644 --- a/in-vehicle-digital-twin/src/main.rs +++ b/in-vehicle-digital-twin/src/main.rs @@ -6,14 +6,12 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::RwLock; use proto::digitaltwin::digital_twin_server::DigitalTwinServer; -use proto::provider::provider_server::ProviderServer; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; use tonic::transport::Server; mod digitaltwin_impl; -mod provider_impl; const IN_VEHICLE_DIGITAL_TWIN_ADDR: &str = "[::1]:50010"; @@ -26,11 +24,9 @@ async fn main() -> Result<(), Box> { // Setup the HTTP server. let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_ADDR.parse()?; - let provider_impl = provider_impl::ProviderImpl::default(); let digitaltwin_impl = digitaltwin_impl::DigitalTwinImpl { entity_map: Arc::new(RwLock::new(HashMap::new())) }; let server_future = Server::builder() - .add_service(ProviderServer::new(provider_impl)) .add_service(DigitalTwinServer::new(digitaltwin_impl)) .serve(addr); info!("The HTTP server is listening on address '{IN_VEHICLE_DIGITAL_TWIN_ADDR}'"); diff --git a/in-vehicle-digital-twin/src/provider_impl.rs b/in-vehicle-digital-twin/src/provider_impl.rs deleted file mode 100644 index b1d0b380..00000000 --- a/in-vehicle-digital-twin/src/provider_impl.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// SPDX-License-Identifier: MIT - -use log::warn; -use proto::provider::provider_server::Provider; -use proto::provider::{ - GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, - SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, -}; -use tonic::{Request, Response, Status}; - -#[derive(Debug, Default)] -pub struct ProviderImpl {} - -#[tonic::async_trait] -impl Provider for ProviderImpl { - /// Subscribe implementation. - /// - /// # Arguments - /// * `request` - Subscribe request. - async fn subscribe( - &self, - request: Request, - ) -> Result, Status> { - warn!("Got a subscribe request: {request:?}"); - - Err(Status::unimplemented("subscribe has not been implemented")) - } - - /// Unsubscribe implementation. - /// - /// # Arguments - /// * `request` - Unsubscribe request. - async fn unsubscribe( - &self, - request: Request, - ) -> Result, Status> { - warn!("Got an unsubscribe request: {request:?}"); - - Err(Status::unimplemented("unsubscribe has not been implemented")) - } - - /// Get implementation. - /// - /// # Arguments - /// * `request` - Get request. - async fn get(&self, request: Request) -> Result, Status> { - warn!("Got a get request: {request:?}"); - - Err(Status::unimplemented("get has not been implemented")) - } - - /// Set implementation. - /// - /// # Arguments - /// * `request` - Set request. - async fn set(&self, request: Request) -> Result, Status> { - warn!("Got a set request: {request:?}"); - - Err(Status::unimplemented("set has not been implemented")) - } - - /// Invoke implementation. - /// - /// # Arguments - /// * `request` - Invoke request. - async fn invoke( - &self, - request: Request, - ) -> Result, Status> { - warn!("Got an invoke request: {request:?}"); - - Err(Status::unimplemented("invoke has not been implemented")) - } -} diff --git a/proto/Cargo.toml b/proto/Cargo.toml index 743a3cb5..a765f67a 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -9,9 +9,9 @@ edition = "2021" license = "MIT" [dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } prost = { workspace = true } -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [build-dependencies] tonic-build = { workspace = true } diff --git a/proto/build.rs b/proto/build.rs index 22b69677..a4b07283 100644 --- a/proto/build.rs +++ b/proto/build.rs @@ -3,8 +3,6 @@ // SPDX-License-Identifier: MIT fn main() -> Result<(), Box> { - tonic_build::compile_protos("consumer.proto")?; - tonic_build::compile_protos("provider.proto")?; tonic_build::compile_protos("digitaltwin.proto")?; Ok(()) } diff --git a/proto/digitaltwin.proto b/proto/digitaltwin.proto index da72627e..f1ff1b5d 100644 --- a/proto/digitaltwin.proto +++ b/proto/digitaltwin.proto @@ -13,23 +13,25 @@ service DigitalTwin { } message FindByIdRequest { - string entity_id = 1; + string payload = 1; } message FindByIdResponse { - string dtdl = 1; + string payload = 1; } message RegisterRequest { - string dtdl = 1; + string payload = 1; } message RegisterResponse { + string payload = 1; } message UnregisterRequest { - string entity_id = 1; + string payload = 1; } message UnregisterResponse { + string payload = 1; } \ No newline at end of file diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 1b717619..f1d6300d 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -2,20 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -pub mod consumer { - #![allow(clippy::derive_partial_eq_without_eq)] - - tonic::include_proto!("consumer"); -} - pub mod digitaltwin { #![allow(clippy::derive_partial_eq_without_eq)] - tonic::include_proto!("digitaltwin"); } - -pub mod provider { - #![allow(clippy::derive_partial_eq_without_eq)] - - tonic::include_proto!("provider"); -} diff --git a/samples/command/consumer/Cargo.toml b/samples/command/consumer/Cargo.toml index 6c60ea36..6afdcd67 100644 --- a/samples/command/consumer/Cargo.toml +++ b/samples/command/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dtdl-parser = { path = "../../../dtdl-parser" } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } @@ -18,6 +18,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/command/consumer/src/consumer_impl.rs b/samples/command/consumer/src/consumer_impl.rs index 96d1e254..05e842e1 100644 --- a/samples/command/consumer/src/consumer_impl.rs +++ b/samples/command/consumer/src/consumer_impl.rs @@ -3,15 +3,15 @@ // SPDX-License-Identifier: MIT use log::{info, warn}; -use proto::consumer::consumer_server::Consumer; -use proto::consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct ConsumerImpl {} #[tonic::async_trait] -impl Consumer for ConsumerImpl { +impl DigitalTwinConsumer for ConsumerImpl { /// Publish implementation. /// /// # Arguments diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 61473c02..7bb1b62e 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -4,16 +4,15 @@ mod consumer_impl; +use data_exchange::digitaltwin::{FindByIdRequestPayload, FindByIdResponsePayload}; use dt_model_identifiers::sdv_v1 as sdv; -use dtdl_parser::dtmi::{create_dtmi, Dtmi}; -use dtdl_parser::model_parser::ModelParser; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::consumer::consumer_server::ConsumerServer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; -use proto::provider::provider_client::ProviderClient; -use proto::provider::InvokeRequest; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; +use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; use std::net::SocketAddr; use tokio::time::{sleep, Duration}; use tonic::transport::Server; @@ -36,7 +35,7 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) info!("Sending an invoke request on entity {} with payload '{payload} to provider URI {provider_uri}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); - let client_result = ProviderClient::connect(provider_uri.clone()).await; + let client_result = DigitalTwinProviderClient::connect(provider_uri.clone()).await; if client_result.is_err() { warn!("Unable to connect. We will retry in a moment."); sleep(Duration::from_secs(1)).await; @@ -80,59 +79,41 @@ async fn main() -> Result<(), Box> { let addr: SocketAddr = consumer_authority.parse()?; let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = - Server::builder().add_service(ConsumerServer::new(consumer_impl)).serve(addr); + Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_ADDR}'"); // Obtain the DTDL for the send_notification command. info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; + let request_payload = FindByIdRequestPayload { + id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) + }; + let request_payload = match serde_json::to_string(&request_payload) { + Ok(content) => content, + Err(error) => panic!("Failed to serialize the request payload: {error}") + }; let request = tonic::Request::new(FindByIdRequest { - entity_id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + payload: request_payload }); let response = client.find_by_id(request).await?; - let dtdl = response.into_inner().dtdl; + let response_inner = response.into_inner(); + info!("{}", &response_inner.payload); + let response_payload: FindByIdResponsePayload = + serde_json::from_str(&response_inner.payload).map_err(|error| format!("Failed to deserialize the response payload: {error}"))?; debug!("Received the response for the find_by_id request"); - - debug!("Parsing the DTDL."); - let mut parser = ModelParser::new(); - let json_texts = vec![dtdl]; - let model_dict_result = parser.parse(&json_texts); - if let Err(error) = model_dict_result { - panic!("Failed to parse the DTDL: {error}"); - } - let model_dict = model_dict_result.unwrap(); - debug!("The DTDL parser has successfully parsed the DTDL"); - - // Create the id (as a DTMI) for the show-notification command. - let show_notification_command_id: Option = - create_dtmi(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); - if show_notification_command_id.is_none() { - panic!("Unable to create the dtmi"); - } - - // Get the entity from the DTDL for the show-notification command. - let entity_result = model_dict.get(&show_notification_command_id.unwrap()); - if entity_result.is_none() { - panic!("Unable to find the entity"); - } - let entity = entity_result.unwrap(); - - // Get the URI property from the entity. - let uri_property_result = entity.undefined_properties().get(sdv::property::uri::ID); - if uri_property_result.is_none() { - panic!("Unable to find the URI property"); + info!("response_payload: {:?}", response_payload.entity); + let provider_uri; + match response_payload.entity { + Some(content) => { + // TODO: select the right one, rather than just using the first one + provider_uri = content.endpoints[0].uri.clone(); + }, + None => { + panic!("Did not find an entity for the show-notification command"); + } } - let uri_property = uri_property_result.unwrap(); - // Get the value for the URI property. - let uri_property_value_result = uri_property.get("@value"); - if uri_property_value_result.is_none() { - panic!("Unable to find the value for the URI for the show-notification's provider."); - } - let uri_property_value = uri_property_value_result.unwrap(); - let uri_str_option = uri_property_value.as_str(); - let provider_uri = String::from(uri_str_option.unwrap()); info!("The URI for the show-notification command's provider is {provider_uri}"); let consumer_uri = format!("http://{CONSUMER_ADDR}"); // Devskim: ignore DS137138 diff --git a/samples/command/dtdl/content/show_notification.json b/samples/command/dtdl/content/show_notification.json index 7f69cb1e..e11e1f7e 100644 --- a/samples/command/dtdl/content/show_notification.json +++ b/samples/command/dtdl/content/show_notification.json @@ -19,6 +19,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Invoke" ] } ] diff --git a/samples/command/provider/Cargo.toml b/samples/command/provider/Cargo.toml index bb2d8040..1a0fc94b 100644 --- a/samples/command/provider/Cargo.toml +++ b/samples/command/provider/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } @@ -18,6 +19,7 @@ log = { workspace = true} parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 4c02b0ea..6771d520 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -4,13 +4,14 @@ mod provider_impl; +use data_exchange::digitaltwin::{Entity, Endpoint, RegisterRequestPayload}; +use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; -use ibeji_common::{find_full_path, retrieve_dtdl}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::RegisterRequest; -use proto::provider::provider_server::ProviderServer; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; use tonic::transport::Server; @@ -28,22 +29,50 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - debug!("Preparing the Provider's DTDL."); - let provider_dtdl_path = find_full_path("content/show_notification.json")?; - let dtdl = retrieve_dtdl(&provider_dtdl_path)?; - debug!("Prepared the Provider's DTDL."); + let mut operations = Vec::new(); + operations.push(String::from("Get")); + operations.push(String::from("Set")); + + let endpoint = Endpoint { + protocol: String::from("grpc"), + operations, + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) + }; + + let mut endpoints = Vec::new(); + endpoints.push(endpoint); + + let entity = Entity { + name: String::from("ShowNotification"), + id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + description: String::from("Show a notification on the HMI."), + endpoints + }; + + let mut entities = Vec::new(); + entities.push(entity); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.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(ProviderServer::new(provider_impl)).serve(addr); + Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); info!("The HTTP server is listening on address '{PROVIDER_ADDR}'"); 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 { dtdl }); + let request_payload = RegisterRequestPayload { + entities + }; + let request_payload = match serde_json::to_string(&request_payload) { + Ok(content) => content, + Err(error) => panic!("Failed to serialize the request payload: {error}") + }; + let request = tonic::Request::new(RegisterRequest { + payload: request_payload + }); let _response = client.register(request).await?; debug!("The Provider's DTDL has been registered."); diff --git a/samples/command/provider/src/provider_impl.rs b/samples/command/provider/src/provider_impl.rs index bd29774c..802bbbb5 100644 --- a/samples/command/provider/src/provider_impl.rs +++ b/samples/command/provider/src/provider_impl.rs @@ -4,9 +4,10 @@ use log::{info, warn}; use parking_lot::Mutex; -use proto::consumer::{consumer_client::ConsumerClient, RespondRequest}; -use proto::provider::{ - provider_server::Provider, GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; +use samples_proto::sample_grpc::v1::digital_twin_consumer::RespondRequest; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProvider; +use samples_proto::sample_grpc::v1::digital_twin_provider::{ GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; @@ -21,7 +22,7 @@ pub struct ProviderImpl { } #[tonic::async_trait] -impl Provider for ProviderImpl { +impl DigitalTwinProvider for ProviderImpl { /// Subscribe implementation. /// /// # Arguments @@ -89,7 +90,7 @@ impl Provider for ProviderImpl { info!("Notification: '{payload}'"); tokio::spawn(async move { - let client_result = ConsumerClient::connect(consumer_uri.clone()).await; + let client_result = DigitalTwinConsumerClient::connect(consumer_uri.clone()).await; if client_result.is_err() { return Err(Status::internal(format!("{:?}", client_result.unwrap_err()))); } diff --git a/samples/mixed/consumer/Cargo.toml b/samples/mixed/consumer/Cargo.toml index e1cdc2fe..a7aacd71 100644 --- a/samples/mixed/consumer/Cargo.toml +++ b/samples/mixed/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dtdl-parser = { path = "../../../dtdl-parser" } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } @@ -18,6 +18,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/mixed/consumer/src/consumer_impl.rs b/samples/mixed/consumer/src/consumer_impl.rs index 2fe6637c..306471fa 100644 --- a/samples/mixed/consumer/src/consumer_impl.rs +++ b/samples/mixed/consumer/src/consumer_impl.rs @@ -3,15 +3,15 @@ // SPDX-License-Identifier: MIT use log::info; -use proto::consumer::consumer_server::Consumer; -use proto::consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct ConsumerImpl {} #[tonic::async_trait] -impl Consumer for ConsumerImpl { +impl DigitalTwinConsumer for ConsumerImpl { /// Publish implementation. /// /// # Arguments diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 7da83a2b..4a683f24 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -9,11 +9,11 @@ use dtdl_parser::dtmi::{create_dtmi, Dtmi}; use dtdl_parser::model_parser::ModelParser; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::consumer::consumer_server::ConsumerServer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; -use proto::provider::provider_client::ProviderClient; -use proto::provider::{InvokeRequest, SetRequest, SubscribeRequest}; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; +use samples_proto::sample_grpc::v1::digital_twin_provider::{InvokeRequest, SetRequest, SubscribeRequest}; use std::net::SocketAddr; use tokio::time::{sleep, Duration}; use tonic::transport::Server; @@ -37,7 +37,7 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) info!("Sending an invoke request on entity {} with payload '{payload} to provider URI {provider_uri}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); - let client_result = ProviderClient::connect(provider_uri.clone()).await; + let client_result = DigitalTwinProviderClient::connect(provider_uri.clone()).await; if client_result.is_err() { warn!("Unable to connect. We will retry in a moment."); sleep(Duration::from_secs(1)).await; @@ -81,7 +81,7 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { info!("Sending a set request for entity id {} to the value '{is_active}' to provider URI {provider_uri}", sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID); - let client_result = ProviderClient::connect(provider_uri.clone()).await; + let client_result = DigitalTwinProviderClient::connect(provider_uri.clone()).await; if client_result.is_err() { warn!("Unable to connect. We will retry in a moment."); sleep(Duration::from_secs(1)).await; @@ -169,7 +169,7 @@ async fn send_subscribe_request( consumer_uri: &str, ) -> Result<(), Box> { info!("Sending a subscribe request for entity id {entity_id} to provider URI {provider_uri}"); - let mut client = ProviderClient::connect(provider_uri.to_string()).await?; + let mut client = DigitalTwinProviderClient::connect(provider_uri.to_string()).await?; let request = tonic::Request::new(SubscribeRequest { entity_id: String::from(entity_id), consumer_uri: consumer_uri.to_string(), @@ -190,7 +190,7 @@ async fn main() -> Result<(), Box> { let addr: SocketAddr = CONSUMER_ADDR.parse()?; let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = - Server::builder().add_service(ConsumerServer::new(consumer_impl)).serve(addr); + Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_ADDR}'"); let show_notification_command_provider_uri = diff --git a/samples/mixed/dtdl/content/mixed.json b/samples/mixed/dtdl/content/mixed.json index 25e832a5..5a6781bd 100644 --- a/samples/mixed/dtdl/content/mixed.json +++ b/samples/mixed/dtdl/content/mixed.json @@ -16,6 +16,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Subscribe", "Unsubscribe" ] } ] @@ -30,6 +33,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Set", "Subscribe", "Unsubscribe" ] } ] @@ -53,6 +59,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Subscribe", "Unsubscribe" ] } ] @@ -79,6 +88,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Invoke" ] } ] diff --git a/samples/mixed/provider/Cargo.toml b/samples/mixed/provider/Cargo.toml index 39980461..9358822f 100644 --- a/samples/mixed/provider/Cargo.toml +++ b/samples/mixed/provider/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } @@ -18,6 +19,7 @@ log = { workspace = true } parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true , features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index fb91802a..f2e8aea7 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -10,11 +10,11 @@ use env_logger::{Builder, Target}; use ibeji_common::{find_full_path, retrieve_dtdl}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use proto::consumer::consumer_client::ConsumerClient; -use proto::consumer::PublishRequest; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; +use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::RegisterRequest; -use proto::provider::provider_server::ProviderServer; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; @@ -45,7 +45,7 @@ async fn publish(subscription_map: Arc>, entity_id: &str, "Sending a publish request for {entity_id} with value {value} to consumer URI {url}" ); - let client_result = ConsumerClient::connect(url).await; + let client_result = DigitalTwinConsumerClient::connect(url).await; if client_result.is_err() { warn!("Unable to connect. We will retry in a moment."); sleep(Duration::from_secs(1)).await; @@ -136,7 +136,7 @@ async fn main() -> Result<(), Box> { let provider_impl = ProviderImpl { subscription_map: subscription_map.clone(), vehicle: vehicle.clone() }; let server_future = - Server::builder().add_service(ProviderServer::new(provider_impl)).serve(addr); + Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); info!("The HTTP server is listening on address '{PROVIDER_ADDR}'"); info!("Sending a register request with the Provider's DTDL to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}"); diff --git a/samples/mixed/provider/src/provider_impl.rs b/samples/mixed/provider/src/provider_impl.rs index f1375821..0dc72715 100644 --- a/samples/mixed/provider/src/provider_impl.rs +++ b/samples/mixed/provider/src/provider_impl.rs @@ -5,9 +5,11 @@ use dt_model_identifiers::sdv_v1 as sdv; use log::{debug, info, warn}; use parking_lot::{Mutex, MutexGuard}; -use proto::consumer::{consumer_client::ConsumerClient, RespondRequest}; -use proto::provider::{ - provider_server::Provider, GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; +use samples_proto::sample_grpc::v1::digital_twin_consumer::RespondRequest; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProvider; +use samples_proto::sample_grpc::v1::digital_twin_provider::{ + GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; @@ -47,7 +49,7 @@ impl ProviderImpl { } #[tonic::async_trait] -impl Provider for ProviderImpl { +impl DigitalTwinProvider for ProviderImpl { /// Subscribe implementation. /// /// # Arguments @@ -170,7 +172,7 @@ impl Provider for ProviderImpl { "Sending an invoke response for entity id {entity_id} to consumer URI {consumer_uri} " ); - let client_result = ConsumerClient::connect(consumer_uri).await; + let client_result = DigitalTwinConsumerClient::connect(consumer_uri).await; if client_result.is_err() { return Err(Status::internal(format!("{:?}", client_result.unwrap_err()))); } diff --git a/samples/property/consumer/Cargo.toml b/samples/property/consumer/Cargo.toml index 1f62eda7..2a749332 100644 --- a/samples/property/consumer/Cargo.toml +++ b/samples/property/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dtdl-parser = { path = "../../../dtdl-parser" } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } @@ -18,6 +18,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/property/consumer/src/consumer_impl.rs b/samples/property/consumer/src/consumer_impl.rs index bfa48039..6675d77d 100644 --- a/samples/property/consumer/src/consumer_impl.rs +++ b/samples/property/consumer/src/consumer_impl.rs @@ -3,15 +3,15 @@ // SPDX-License-Identifier: MIT use log::{info, warn}; -use proto::consumer::consumer_server::Consumer; -use proto::consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct ConsumerImpl {} #[tonic::async_trait] -impl Consumer for ConsumerImpl { +impl DigitalTwinConsumer for ConsumerImpl { /// Publish implementation. /// /// # Arguments diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 9a3ec9dc..6f69203c 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -7,11 +7,11 @@ use dtdl_parser::dtmi::{create_dtmi, Dtmi}; use dtdl_parser::model_parser::ModelParser; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use proto::consumer::consumer_server::ConsumerServer; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; -use proto::provider::provider_client::ProviderClient; -use proto::provider::SubscribeRequest; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; +use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; use std::net::SocketAddr; use tonic::transport::Server; @@ -32,7 +32,7 @@ async fn main() -> Result<(), Box> { let addr: SocketAddr = CONSUMER_ADDR.parse()?; let consumer_impl = consumer_impl::ConsumerImpl::default(); let server_future = - Server::builder().add_service(ConsumerServer::new(consumer_impl)).serve(addr); + Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); // Obtain the DTDL for the ambient air temmpterature. info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", @@ -93,7 +93,7 @@ async fn main() -> Result<(), Box> { "Sending a subscribe request for entity id {} to provider URI {uri}", sdv::vehicle::cabin::hvac::ambient_air_temperature::ID ); - let mut client = ProviderClient::connect(uri).await?; + let mut client = DigitalTwinProviderClient::connect(uri).await?; let request = tonic::Request::new(SubscribeRequest { entity_id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), consumer_uri, diff --git a/samples/property/dtdl/content/ambient_air_temperature.json b/samples/property/dtdl/content/ambient_air_temperature.json index a5b62978..6f5b06b4 100644 --- a/samples/property/dtdl/content/ambient_air_temperature.json +++ b/samples/property/dtdl/content/ambient_air_temperature.json @@ -16,6 +16,9 @@ { "@type": "Endpoint", "uri": "http://[::1]:40010", + "communication_protocol": "http", + "schema_kind": "grpc", + "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", "operations": [ "Subscribe", "Unsubscribe" ] } ] diff --git a/samples/property/provider/Cargo.toml b/samples/property/provider/Cargo.toml index 9dcc9dda..4b2aaa2a 100644 --- a/samples/property/provider/Cargo.toml +++ b/samples/property/provider/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } +data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } @@ -18,6 +19,7 @@ log = { workspace = true} parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 4c54ea3e..e7417df4 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -9,11 +9,11 @@ use env_logger::{Builder, Target}; use ibeji_common::{find_full_path, retrieve_dtdl}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use proto::consumer::consumer_client::ConsumerClient; -use proto::consumer::PublishRequest; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; +use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::RegisterRequest; -use proto::provider::provider_server::ProviderServer; +use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; @@ -52,7 +52,7 @@ fn start_ambient_air_temperature_data_stream(subscription_map: Arc Result<(), Box> { 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(ProviderServer::new(provider_impl)).serve(addr); + Server::builder().add_service(DigitalTwinProviderServer::new(provider_impl)).serve(addr); info!("The HTTP server is listening on address '{PROVIDER_ADDR}'"); info!("Sending a register request with the Provider's DTDL to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}"); diff --git a/samples/property/provider/src/provider_impl.rs b/samples/property/provider/src/provider_impl.rs index dde20ade..4ad14b1f 100644 --- a/samples/property/provider/src/provider_impl.rs +++ b/samples/property/provider/src/provider_impl.rs @@ -4,8 +4,8 @@ use log::{debug, info, warn}; use parking_lot::{Mutex, MutexGuard}; -use proto::provider::{ - provider_server::Provider, GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, +use samples_proto::sample_grpc::v1::digital_twin_provider::{ + digital_twin_provider_server::DigitalTwinProvider, GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; @@ -20,7 +20,7 @@ pub struct ProviderImpl { } #[tonic::async_trait] -impl Provider for ProviderImpl { +impl DigitalTwinProvider for ProviderImpl { /// Subscribe implementation. /// /// # Arguments diff --git a/samples/proto/Cargo.toml b/samples/proto/Cargo.toml new file mode 100644 index 00000000..b5e9cc25 --- /dev/null +++ b/samples/proto/Cargo.toml @@ -0,0 +1,17 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +[package] +name = "samples_proto" +version = "1.0.0" +edition = "2021" +license = "MIT" + +[dependencies] +tonic = { workspace = true } +prost = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[build-dependencies] +tonic-build = { workspace = true } diff --git a/samples/proto/build.rs b/samples/proto/build.rs new file mode 100644 index 00000000..da6e3d0b --- /dev/null +++ b/samples/proto/build.rs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +fn main() -> Result<(), Box> { + tonic_build::compile_protos("sample_grpc/v1/digital_twin_consumer.proto")?; + tonic_build::compile_protos("sample_grpc/v1/digital_twin_provider.proto")?; + Ok(()) +} diff --git a/proto/consumer.proto b/samples/proto/sample_grpc/v1/digital_twin_consumer.proto similarity index 88% rename from proto/consumer.proto rename to samples/proto/sample_grpc/v1/digital_twin_consumer.proto index d81c2c13..b34c4863 100644 --- a/proto/consumer.proto +++ b/samples/proto/sample_grpc/v1/digital_twin_consumer.proto @@ -4,9 +4,9 @@ syntax = "proto3"; -package consumer; +package digital_twin_consumer; -service Consumer { +service DigitalTwinConsumer { rpc Publish (PublishRequest) returns (PublishResponse); rpc Respond (RespondRequest) returns (RespondResponse); } diff --git a/proto/provider.proto b/samples/proto/sample_grpc/v1/digital_twin_provider.proto similarity index 94% rename from proto/provider.proto rename to samples/proto/sample_grpc/v1/digital_twin_provider.proto index a33f111c..a2363dd1 100644 --- a/proto/provider.proto +++ b/samples/proto/sample_grpc/v1/digital_twin_provider.proto @@ -4,9 +4,9 @@ syntax = "proto3"; -package provider; +package digital_twin_provider; -service Provider { +service DigitalTwinProvider { rpc Subscribe (SubscribeRequest) returns (SubscribeResponse); rpc Unsubscribe (UnsubscribeRequest) returns (UnsubscribeResponse); rpc Get (GetRequest) returns (GetResponse); diff --git a/samples/proto/src/lib.rs b/samples/proto/src/lib.rs new file mode 100644 index 00000000..5e12caa4 --- /dev/null +++ b/samples/proto/src/lib.rs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +#![allow(clippy::derive_partial_eq_without_eq)] + +pub mod sample_grpc { + pub mod v1 { + pub mod digital_twin_consumer { + tonic::include_proto!("digital_twin_consumer"); + } + + pub mod digital_twin_provider { + tonic::include_proto!("digital_twin_provider"); + } + } +} From 4dcbecb71369531a604757e448cd224adcb0aab5 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 5 May 2023 18:26:14 -0700 Subject: [PATCH 02/41] Make protocol agnostic --- Cargo.toml | 3 +- data-exchange/Cargo.toml | 12 -- data-exchange/src/lib.rs | 50 ------ in-vehicle-digital-twin/Cargo.toml | 1 - .../src/digitaltwin_impl.rs | 148 ++++++------------ in-vehicle-digital-twin/src/main.rs | 2 +- proto/digitaltwin.proto | 25 ++- samples/command/consumer/Cargo.toml | 1 - samples/command/consumer/src/main.rs | 22 +-- samples/command/provider/Cargo.toml | 1 - samples/command/provider/src/main.rs | 29 ++-- samples/mixed/consumer/Cargo.toml | 1 - samples/mixed/provider/Cargo.toml | 1 - samples/property/consumer/Cargo.toml | 1 - samples/property/provider/Cargo.toml | 1 - 15 files changed, 89 insertions(+), 209 deletions(-) delete mode 100644 data-exchange/Cargo.toml delete mode 100644 data-exchange/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 960cef63..8e2c5f3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,7 @@ members = [ "common", "common-test", - "dt-model/dt-model-identifiers", - "data-exchange", + "dt-model/dt-model-identifiers", "dtdl-parser", "in-vehicle-digital-twin", "samples/proto", diff --git a/data-exchange/Cargo.toml b/data-exchange/Cargo.toml deleted file mode 100644 index a87063bb..00000000 --- a/data-exchange/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT license. -# SPDX-License-Identifier: MIT - -[package] -name = "data-exchange" -version = "0.1.0" -edition = "2021" -license = "MIT" - -[dependencies] -serde = { workspace = true, features = ["derive"] } diff --git a/data-exchange/src/lib.rs b/data-exchange/src/lib.rs deleted file mode 100644 index c7b97823..00000000 --- a/data-exchange/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// SPDX-License-Identifier: MIT - -pub mod digitaltwin { - use serde::{Deserialize, Serialize}; - - #[derive(Deserialize, Serialize, Debug, Clone)] - pub struct Endpoint { - pub protocol: String, - pub operations: Vec, - pub uri: String, - pub context: String, - } - - #[derive(Deserialize, Serialize, Debug, Clone)] - pub struct Entity { - pub name: String, - pub id: String, - pub description: String, - pub endpoints: Vec, - } - - #[derive(Deserialize, Serialize)] - pub struct FindByIdRequestPayload { - pub id: String, - } - - #[derive(Deserialize, Serialize)] - pub struct FindByIdResponsePayload { - pub entity: Option - } - - #[derive(Deserialize, Serialize)] - pub struct RegisterRequestPayload { - pub entities: Vec, - } - - #[derive(Deserialize, Serialize)] - pub struct RegisterResponsePayload { - } - - #[derive(Deserialize, Serialize)] - pub struct UnregisterRequestPayload { - } - - #[derive(Deserialize, Serialize)] - pub struct UnregisterResponsePayload { - } -} diff --git a/in-vehicle-digital-twin/Cargo.toml b/in-vehicle-digital-twin/Cargo.toml index 83ed7120..514079f2 100644 --- a/in-vehicle-digital-twin/Cargo.toml +++ b/in-vehicle-digital-twin/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../data-exchange" } env_logger= { workspace = true } ibeji-common = { path = "../common" } ibeji-common_test = { path = "../common-test" } diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 05008f89..4fbf4e3f 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -9,16 +9,16 @@ use log::{debug, info, log_enabled, warn}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use proto::digitaltwin::digital_twin_server::DigitalTwin; use proto::digitaltwin::{ + EntityAccessInfo, FindByIdRequest, FindByIdResponse, RegisterRequest, RegisterResponse, UnregisterRequest, UnregisterResponse}; -use data_exchange::digitaltwin::{Entity, FindByIdRequestPayload, FindByIdResponsePayload, RegisterRequestPayload}; use std::collections::HashMap; use std::sync::Arc; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct DigitalTwinImpl { - pub entity_map: Arc>>, + pub entity_access_info_map: Arc>>, } #[tonic::async_trait] @@ -31,45 +31,23 @@ impl DigitalTwin for DigitalTwinImpl { &self, request: Request, ) -> Result, Status> { - let request_inner = request.into_inner(); - - let payload: FindByIdRequestPayload = match serde_json::from_str(&request_inner.payload) { - Ok(content) => content, - Err(error) => { - return Err(Status::internal(format!( - "Unexpected error with the payload: {error:?}" - ))) - } - }; + let request_inner = request.into_inner(); - let entity_id = payload.id; + let entity_id = request_inner.id; info!("Received a find_by_id request for entity id {entity_id}"); - let entity: Option; + let entity_access_info; // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = self.entity_map.read(); - entity = lock.get(&entity_id).map(|value| value.clone()); + let lock: RwLockReadGuard> = self.entity_access_info_map.read(); + entity_access_info = lock.get(&entity_id).map(|value| value.clone()); } - let response_payload = FindByIdResponsePayload { - entity - }; - - let payload = match serde_json::to_string(&response_payload) { - Ok(content) => content, - Err(error) => { - return Err(Status::internal(format!( - "Unexpected error with the conversion to JSON for entity {entity_id}: {error}" - ))) - } - }; - - info!("{}", payload); + info!("{:?}", entity_access_info); - let response = FindByIdResponse { payload }; + let response = FindByIdResponse { entity_access_info }; debug!("Responded to the find_by_id request."); @@ -86,27 +64,18 @@ impl DigitalTwin for DigitalTwinImpl { ) -> Result, Status> { let request_inner = request.into_inner(); - let payload: RegisterRequestPayload = match serde_json::from_str(&request_inner.payload) { - Ok(content) => content, - Err(error) => { - return Err(Status::internal(format!( - "Unexpected error with the payload: {error:?}" - ))) - } - }; - - for entity in &payload.entities { - info!("Received a register request for the the entity:\n{}", &entity.id); + for entity_access_info in &request_inner.entity_access_info_list { + info!("Received a register request for the the entity:\n{}", &entity_access_info.id); - match self.register_entity(entity.clone()) { + match self.register_entity(entity_access_info.clone()) { Ok(_) => { - self.register_entity(entity.clone()).map_err(|error| return Status::internal(format!("{}", error)))? + self.register_entity(entity_access_info.clone()).map_err(|error| return Status::internal(format!("{}", error)))? }, Err(error) => return Err(Status::internal(error)) }; } - let response = RegisterResponse {payload: String::from("")}; + let response = RegisterResponse {}; debug!("Completed the register request."); @@ -133,22 +102,22 @@ impl DigitalTwinImpl { /// /// # Arguments /// * `entity` - The entity. - fn register_entity(&self, entity: Entity) -> Result<(), String> { + fn register_entity(&self, entity_access_info: EntityAccessInfo) -> Result<(), String> { // This block controls the lifetime of the lock. { - let mut lock: RwLockWriteGuard> = self.entity_map.write(); - match lock.get(&entity.id) { + let mut lock: RwLockWriteGuard> = self.entity_access_info_map.write(); + match lock.get(&entity_access_info.id) { Some(_) => { // TODO: merge existing contents with new contents }, None => { - lock.insert(entity.id.clone(), entity.clone()); + lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } }; } if log_enabled!(Debug) { - debug!("Registered entity {}", &entity.id); + debug!("Registered entity {}", &entity_access_info.id); } Ok(()) @@ -159,7 +128,7 @@ impl DigitalTwinImpl { mod digitaltwin_impl_tests { use super::*; use ibeji_common_test::set_dtdl_path; - use data_exchange::digitaltwin::{Endpoint, FindByIdResponsePayload}; + use proto::digitaltwin::EndpointInfo; #[tokio::test] async fn find_by_id_test() { @@ -169,51 +138,44 @@ mod digitaltwin_impl_tests { operations.push(String::from("Subscribe")); operations.push(String::from("Unsubscribe")); - let endpoint = Endpoint { + let endpoint_info = EndpointInfo { protocol: String::from("grpc"), uri: String::from("http://[::1]:40010"), - context: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; - let mut endpoints = Vec::new(); - endpoints.push(endpoint); + let mut endpoint_info_list = Vec::new(); + endpoint_info_list.push(endpoint_info); - let entity = Entity { - digital_twin_model: String::from("dtmi:svd:vehcile;1"), + let entity_access_info= EntityAccessInfo { name: String::from("AmbientAirTemperature"), - id: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), description: String::from("Ambient air temperature"), - endpoints + endpoint_info_list }; - let entity_map = Arc::new(RwLock::new(HashMap::new())); + let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); - let digital_twin_impl = DigitalTwinImpl { entity_map: entity_map.clone() }; + 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_map.write(); - lock.insert(entity.id.clone(), entity.clone()); + let mut lock: RwLockWriteGuard> = entity_access_info_map.write(); + lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } - let request_payload = FindByIdRequestPayload { - id: entity.id.clone() - }; - - let request_payload_result = serde_json::to_string(&request_payload); - assert!(request_payload_result.is_ok()); - - let request = tonic::Request::new(FindByIdRequest { payload: request_payload_result.unwrap()}); + 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(); - let response_payload_result: Result = serde_json::from_str(&response_inner.payload); - assert!(response_payload_result.is_ok()); + assert!(response_inner.entity_access_info.is_some()); - // assert!(!response_payload.entity.is_empty()); + assert!(response_inner.entity_access_info.unwrap().id == "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"); + + // TODO: add check } #[tokio::test] @@ -224,51 +186,43 @@ mod digitaltwin_impl_tests { operations.push(String::from("Subscribe")); operations.push(String::from("Unsubscribe")); - let endpoint = Endpoint { + let endpoint_info = EndpointInfo { protocol: String::from("grpc"), uri: String::from("http://[::1]:40010"), - context: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; - let mut endpoints = Vec::new(); - endpoints.push(endpoint); + let mut endpoint_info_list = Vec::new(); + endpoint_info_list.push(endpoint_info); - let entity = Entity { - digital_twin_model: String::from("dtmi:svd:vehcile;1"), + let entity_access_info = EntityAccessInfo { name: String::from("AmbientAirTemperature"), - id: String::from("dtmi:sdv:Vehicle:Cabin:HAVC:AmbientAirTemperature;1"), + id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), description: String::from("Ambient air temperature"), - endpoints + endpoint_info_list }; - let mut entities = Vec::new(); - entities.push(entity.clone()); + let mut entity_access_info_list = Vec::new(); + entity_access_info_list.push(entity_access_info.clone()); - let entity_map = Arc::new(RwLock::new(HashMap::new())); + let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); - let digital_twin_impl = DigitalTwinImpl { entity_map: entity_map.clone() }; + 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_map.write(); - lock.insert(entity.id.clone(), entity.clone()); + let mut lock: RwLockWriteGuard> = entity_access_info_map.write(); + lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } - let register_request_payload = RegisterRequestPayload { - entities: entities.clone() - }; - - let request_payload_result = serde_json::to_string(®ister_request_payload); - assert!(request_payload_result.is_ok()); - - let request = tonic::Request::new(RegisterRequest { payload: request_payload_result.unwrap() }); + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); let result = digital_twin_impl.register(request).await; assert!(result.is_ok()); // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = entity_map.read(); + let lock: RwLockReadGuard> = entity_access_info_map.read(); // Make sure that we populated the entity map from the contents of the DTDL. assert!(lock.len() == 1, "expected length was 1, actual length is {}", lock.len()); } diff --git a/in-vehicle-digital-twin/src/main.rs b/in-vehicle-digital-twin/src/main.rs index d4d32715..7ecc5e8f 100644 --- a/in-vehicle-digital-twin/src/main.rs +++ b/in-vehicle-digital-twin/src/main.rs @@ -25,7 +25,7 @@ async fn main() -> Result<(), Box> { // Setup the HTTP server. let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_ADDR.parse()?; let digitaltwin_impl = - digitaltwin_impl::DigitalTwinImpl { entity_map: Arc::new(RwLock::new(HashMap::new())) }; + digitaltwin_impl::DigitalTwinImpl { entity_access_info_map: Arc::new(RwLock::new(HashMap::new())) }; let server_future = Server::builder() .add_service(DigitalTwinServer::new(digitaltwin_impl)) .serve(addr); diff --git a/proto/digitaltwin.proto b/proto/digitaltwin.proto index f1ff1b5d..54dd2794 100644 --- a/proto/digitaltwin.proto +++ b/proto/digitaltwin.proto @@ -12,26 +12,39 @@ service DigitalTwin { rpc Unregister (UnregisterRequest) returns (UnregisterResponse); } +message EndpointInfo { + string protocol = 1; + repeated string operations = 2; + string uri = 3; + string context = 4; +} + +message EntityAccessInfo { + string name = 1; + string id = 2; + string description = 3; + repeated EndpointInfo endpointInfoList = 4; +} + message FindByIdRequest { - string payload = 1; + string id = 1; } message FindByIdResponse { - string payload = 1; + // optional + EntityAccessInfo entityAccessInfo = 1; } message RegisterRequest { - string payload = 1; + repeated EntityAccessInfo entityAccessInfoList = 1; } message RegisterResponse { - string payload = 1; } message UnregisterRequest { - string payload = 1; + string id = 1; } message UnregisterResponse { - string payload = 1; } \ No newline at end of file diff --git a/samples/command/consumer/Cargo.toml b/samples/command/consumer/Cargo.toml index 6afdcd67..4176993f 100644 --- a/samples/command/consumer/Cargo.toml +++ b/samples/command/consumer/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 7bb1b62e..a0339514 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -4,7 +4,6 @@ mod consumer_impl; -use data_exchange::digitaltwin::{FindByIdRequestPayload, FindByIdResponsePayload}; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; @@ -82,32 +81,23 @@ async fn main() -> Result<(), Box> { Server::builder().add_service(DigitalTwinConsumerServer::new(consumer_impl)).serve(addr); info!("The HTTP server is listening on address '{CONSUMER_ADDR}'"); - // Obtain the DTDL for the send_notification command. info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request_payload = FindByIdRequestPayload { - id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) - }; - let request_payload = match serde_json::to_string(&request_payload) { - Ok(content) => content, - Err(error) => panic!("Failed to serialize the request payload: {error}") - }; + let request = tonic::Request::new(FindByIdRequest { - payload: request_payload + id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) }); let response = client.find_by_id(request).await?; let response_inner = response.into_inner(); - info!("{}", &response_inner.payload); - let response_payload: FindByIdResponsePayload = - serde_json::from_str(&response_inner.payload).map_err(|error| format!("Failed to deserialize the response payload: {error}"))?; debug!("Received the response for the find_by_id request"); - info!("response_payload: {:?}", response_payload.entity); + info!("response_payload: {:?}", response_inner.entity_access_info); + let provider_uri; - match response_payload.entity { + match response_inner.entity_access_info { Some(content) => { // TODO: select the right one, rather than just using the first one - provider_uri = content.endpoints[0].uri.clone(); + provider_uri = content.endpoint_info_list[0].uri.clone(); }, None => { panic!("Did not find an entity for the show-notification command"); diff --git a/samples/command/provider/Cargo.toml b/samples/command/provider/Cargo.toml index 1a0fc94b..1801e2ac 100644 --- a/samples/command/provider/Cargo.toml +++ b/samples/command/provider/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 6771d520..a39d7d0c 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -4,13 +4,12 @@ mod provider_impl; -use data_exchange::digitaltwin::{Entity, Endpoint, RegisterRequestPayload}; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::RegisterRequest; +use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; @@ -33,25 +32,25 @@ async fn main() -> Result<(), Box> { operations.push(String::from("Get")); operations.push(String::from("Set")); - let endpoint = Endpoint { + let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations, uri: String::from("http://[::1]:40010"), context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) }; - let mut endpoints = Vec::new(); - endpoints.push(endpoint); + let mut endpoint_info_list = Vec::new(); + endpoint_info_list.push(endpoint_info); - let entity = Entity { + let entity_access_info = EntityAccessInfo { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoints + endpoint_info_list }; - let mut entities = Vec::new(); - entities.push(entity); + let mut entity_access_info_list = Vec::new(); + entity_access_info_list.push(entity_access_info); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; @@ -63,16 +62,10 @@ async fn main() -> Result<(), Box> { 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_payload = RegisterRequestPayload { - entities - }; - let request_payload = match serde_json::to_string(&request_payload) { - Ok(content) => content, - Err(error) => panic!("Failed to serialize the request payload: {error}") - }; + let request = tonic::Request::new(RegisterRequest { - payload: request_payload - }); + entity_access_info_list + }); let _response = client.register(request).await?; debug!("The Provider's DTDL has been registered."); diff --git a/samples/mixed/consumer/Cargo.toml b/samples/mixed/consumer/Cargo.toml index a7aacd71..79a58793 100644 --- a/samples/mixed/consumer/Cargo.toml +++ b/samples/mixed/consumer/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } diff --git a/samples/mixed/provider/Cargo.toml b/samples/mixed/provider/Cargo.toml index 9358822f..ae5b9b10 100644 --- a/samples/mixed/provider/Cargo.toml +++ b/samples/mixed/provider/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } diff --git a/samples/property/consumer/Cargo.toml b/samples/property/consumer/Cargo.toml index 2a749332..2c0d2f7c 100644 --- a/samples/property/consumer/Cargo.toml +++ b/samples/property/consumer/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } iref = { workspace = true } diff --git a/samples/property/provider/Cargo.toml b/samples/property/provider/Cargo.toml index 4b2aaa2a..67b53e8c 100644 --- a/samples/property/provider/Cargo.toml +++ b/samples/property/provider/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -data-exchange = { path = "../../../data-exchange" } dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } From 2e245fdafac5859f432e8556eadf626f7b82948f Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 8 May 2023 15:24:18 -0700 Subject: [PATCH 03/41] Make protocol agnostic --- Cargo.toml | 8 +-- proto/digitaltwin.proto | 4 +- samples/command/consumer/src/main.rs | 3 +- samples/command/provider/src/main.rs | 1 - samples/mixed/consumer/src/main.rs | 54 ++++----------- samples/mixed/provider/src/main.rs | 95 ++++++++++++++++++++++++--- samples/property/consumer/src/main.rs | 63 +++++------------- samples/property/provider/src/main.rs | 36 +++++++--- 8 files changed, 152 insertions(+), 112 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8e2c5f3e..ff7db804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,10 +13,10 @@ members = [ "samples/proto", "samples/command/consumer", "samples/command/provider", -# "samples/mixed/consumer", -# "samples/mixed/provider", -# "samples/property/consumer", -# "samples/property/provider" + "samples/mixed/consumer", + "samples/mixed/provider", + "samples/property/consumer", + "samples/property/provider" ] [workspace.dependencies] diff --git a/proto/digitaltwin.proto b/proto/digitaltwin.proto index 54dd2794..9a77b9bd 100644 --- a/proto/digitaltwin.proto +++ b/proto/digitaltwin.proto @@ -31,7 +31,6 @@ message FindByIdRequest { } message FindByIdResponse { - // optional EntityAccessInfo entityAccessInfo = 1; } @@ -44,6 +43,9 @@ message RegisterResponse { message UnregisterRequest { string id = 1; + string protocol = 2; + string uri = 3; + string context = 4; } message UnregisterResponse { diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index a0339514..1e545b03 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -84,7 +84,6 @@ async fn main() -> Result<(), Box> { info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = tonic::Request::new(FindByIdRequest { id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) }); @@ -100,7 +99,7 @@ async fn main() -> Result<(), Box> { provider_uri = content.endpoint_info_list[0].uri.clone(); }, None => { - panic!("Did not find an entity for the show-notification command"); + panic!("Did not find an entity for the ShowNotification command"); } } diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index a39d7d0c..76ae94cc 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -62,7 +62,6 @@ async fn main() -> Result<(), Box> { 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 }); diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 4a683f24..b3899570 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -5,8 +5,6 @@ mod consumer_impl; use dt_model_identifiers::sdv_v1 as sdv; -use dtdl_parser::dtmi::{create_dtmi, Dtmi}; -use dtdl_parser::model_parser::ModelParser; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; @@ -115,49 +113,23 @@ async fn get_provider_uri(entity_id: &str) -> Result { let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI) .await .map_err(|error| format!("{error}"))?; - let request = tonic::Request::new(FindByIdRequest { entity_id: String::from(entity_id) }); + let request = tonic::Request::new(FindByIdRequest { id: String::from(entity_id) }); let response = client.find_by_id(request).await.map_err(|error| format!("{error}"))?; - let dtdl = response.into_inner().dtdl; + let response_inner = response.into_inner(); debug!("Received the response for the find_by_id request"); - - debug!("Parsing the DTDL."); - let mut parser = ModelParser::new(); - let json_texts = vec![dtdl]; - let model_dict_result = parser.parse(&json_texts); - if let Err(error) = model_dict_result { - return Err(format!("Failed to parse the DTDL: {error}")); - } - let model_dict = model_dict_result.unwrap(); - debug!("The DTDL parser has successfully parsed the DTDL"); - - // Create the id (as a DTMI) for the send_notification command. - let dtmi_id: Option = create_dtmi(entity_id); - if dtmi_id.is_none() { - return Err(String::from("Unable to create the dtmi")); - } - - // Get the entity from the DTDL for the dtmi id. - let entity_result = model_dict.get(&dtmi_id.unwrap()); - if entity_result.is_none() { - return Err(String::from("Unable to find the entity")); - } - let entity = entity_result.unwrap(); - - // Get the URI property from the entity. - let uri_property_result = entity.undefined_properties().get(sdv::property::uri::ID); - if uri_property_result.is_none() { - return Err(String::from("Unable to find the URI property")); + info!("response_payload: {:?}", response_inner.entity_access_info); + + let provider_uri; + match response_inner.entity_access_info { + Some(content) => { + // TODO: select the right one, rather than just using the first one + provider_uri = content.endpoint_info_list[0].uri.clone(); + }, + None => { + panic!("Did not find an entity for the AmbientAirTemperature command"); + } } - let uri_property = uri_property_result.unwrap(); - // Get the value for the URI property. - let uri_property_value_result = uri_property.get("@value"); - if uri_property_value_result.is_none() { - return Err(String::from("Unable to find the value for the URI.")); - } - let uri_property_value = uri_property_value_result.unwrap(); - let uri_str_option = uri_property_value.as_str(); - let provider_uri = String::from(uri_str_option.unwrap()); info!("The provider URI for entity id {entity_id} is {provider_uri}"); Ok(provider_uri) diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index f2e8aea7..1565e949 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -7,13 +7,12 @@ mod vehicle; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; -use ibeji_common::{find_full_path, retrieve_dtdl}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::RegisterRequest; +use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; @@ -124,10 +123,88 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - debug!("Preparing the Provider's DTDL."); - let provider_dtdl_path = find_full_path("content/mixed.json")?; - let dtdl = retrieve_dtdl(&provider_dtdl_path)?; - debug!("Prepared the Provider's DTDL."); + let mut telemetry_operations = Vec::new(); + telemetry_operations.push(String::from("Subscribe")); + telemetry_operations.push(String::from("Unsubscribe")); + + let mut property_operations = Vec::new(); + property_operations.push(String::from("Subscribe")); + property_operations.push(String::from("Unsubscribe")); + property_operations.push(String::from("Get")); + property_operations.push(String::from("Set")); + + let mut command_operations = Vec::new(); + command_operations.push(String::from("Invoke")); + + // AmbientAirTemperature + let ambient_air_temperature_endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + operations: telemetry_operations.clone(), + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + }; + let mut ambient_air_temperature_endpoint_info_list = Vec::new(); + ambient_air_temperature_endpoint_info_list.push(ambient_air_temperature_endpoint_info); + let ambient_air_temperature_access_info = EntityAccessInfo { + name: String::from("AmbientAirTemperature"), + id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), + endpoint_info_list: ambient_air_temperature_endpoint_info_list + }; + + // IsAirConditioningActive + let is_air_conditioning_active_endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + operations: property_operations, + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + }; + let mut is_air_conditioning_active_endpoint_info_list = Vec::new(); + is_air_conditioning_active_endpoint_info_list.push(is_air_conditioning_active_endpoint_info); + let is_air_conditioning_active_access_info = EntityAccessInfo { + name: String::from("IsAirConditioningActive"), + id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), + description: String::from("Is air conditioning active?"), + endpoint_info_list: is_air_conditioning_active_endpoint_info_list + }; + + // HybridBatteryRemaining + let hybrid_battery_remaining_endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + operations: telemetry_operations, + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID) + }; + let mut hybrid_battery_remaining_endpoint_info_list = Vec::new(); + hybrid_battery_remaining_endpoint_info_list.push(hybrid_battery_remaining_endpoint_info); + let hybrid_battery_remaining_access_info = EntityAccessInfo { + name: String::from("HybridBatteryRemaining"), + id: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), + description: String::from("The remaining hybrid battery life."), + endpoint_info_list: hybrid_battery_remaining_endpoint_info_list + }; + + // ShowNotification + let show_notification_endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + operations: command_operations, + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) + }; + let mut show_notification_endpoint_info_list = Vec::new(); + show_notification_endpoint_info_list.push(show_notification_endpoint_info); + let show_notification_access_info = EntityAccessInfo { + name: String::from("ShowNotification"), + id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + description: String::from("Show a notification on the HMI."), + endpoint_info_list: show_notification_endpoint_info_list + }; + + let mut entity_access_info_list = Vec::new(); + entity_access_info_list.push(ambient_air_temperature_access_info); + entity_access_info_list.push(is_air_conditioning_active_access_info); + entity_access_info_list.push(hybrid_battery_remaining_access_info); + entity_access_info_list.push(show_notification_access_info); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; @@ -141,9 +218,11 @@ async fn main() -> Result<(), Box> { 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 { dtdl }); + let request = tonic::Request::new(RegisterRequest { + entity_access_info_list + }); let _response = client.register(request).await?; - debug!("The Provider's DTDL has been registered."); + debug!("The Provider's DTDL has been registered."); 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 6f69203c..dfb1589b 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -3,8 +3,6 @@ // SPDX-License-Identifier: MIT use dt_model_identifiers::sdv_v1 as sdv; -use dtdl_parser::dtmi::{create_dtmi, Dtmi}; -use dtdl_parser::model_parser::ModelParser; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; @@ -39,61 +37,32 @@ async fn main() -> Result<(), Box> { sdv::vehicle::cabin::hvac::ambient_air_temperature::ID); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; let request = tonic::Request::new(FindByIdRequest { - entity_id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }); let response = client.find_by_id(request).await?; - let dtdl = response.into_inner().dtdl; - debug!("Received the response for the find_by_id request."); - - debug!("Parsing the DTDL."); - let mut parser = ModelParser::new(); - let json_texts = vec![dtdl]; - let model_dict_result = parser.parse(&json_texts); - if let Err(error) = model_dict_result { - panic!("Failed to parse the DTDL: {error}"); - } - let model_dict = model_dict_result.unwrap(); - debug!("The DTDL parser has successfully parsed the DTDL."); - - // Create the id (as a DTMI) for the ambient air temperature property. - let ambient_air_temperature_property_id: Option = - create_dtmi(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID); - if ambient_air_temperature_property_id.is_none() { - panic!("Unable to create the dtmi"); - } - - // Get the entity from the DTDL for the ambient air temperature property. - let entity_result = model_dict.get(&ambient_air_temperature_property_id.unwrap()); - if entity_result.is_none() { - panic!("Unable to find the entity"); - } - let entity = entity_result.unwrap(); - - // Get the URI property from the entity. - let uri_property_result = entity.undefined_properties().get(sdv::property::uri::ID); - if uri_property_result.is_none() { - panic!("Unable to find the URI property"); - } - let uri_property = uri_property_result.unwrap(); - - // Get the value for the URI property. - let uri_property_value_result = uri_property.get("@value"); - if uri_property_value_result.is_none() { - panic!("Unable to find the value for the URI for ambient air temperature's provider."); + 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 provider_uri; + match response_inner.entity_access_info { + Some(content) => { + // TODO: select the right one, rather than just using the first one + provider_uri = content.endpoint_info_list[0].uri.clone(); + }, + None => { + panic!("Did not find an entity for the AmbientAirTemperature command"); + } } - let uri_property_value = uri_property_value_result.unwrap(); - let uri_str_option = uri_property_value.as_str(); - let uri = String::from(uri_str_option.unwrap()); - info!("The URI for the ambient air temperature's provider is {uri}"); let consumer_uri = format!("http://{CONSUMER_ADDR}"); // Devskim: ignore DS137138 // Subscribing to the ambient air temperature data feed. info!( - "Sending a subscribe request for entity id {} to provider URI {uri}", + "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(uri).await?; + let mut client = DigitalTwinProviderClient::connect(provider_uri).await?; let request = tonic::Request::new(SubscribeRequest { entity_id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), consumer_uri, diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index e7417df4..a20a51b7 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -6,13 +6,12 @@ mod provider_impl; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; -use ibeji_common::{find_full_path, retrieve_dtdl}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::RegisterRequest; +use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; @@ -101,10 +100,29 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - debug!("Preparing the Provider's DTDL."); - let provider_dtdl_path = find_full_path("content/ambient_air_temperature.json")?; - let dtdl = retrieve_dtdl(&provider_dtdl_path)?; - debug!("Prepared the Provider's DTDL."); + let mut operations = Vec::new(); + operations.push(String::from("Subscribe")); + operations.push(String::from("Unsubscribe")); + + let endpoint_info = EndpointInfo { + protocol: String::from("grpc"), + operations, + uri: String::from("http://[::1]:40010"), + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + }; + + let mut endpoint_info_list = Vec::new(); + endpoint_info_list.push(endpoint_info); + + let entity_access_info = EntityAccessInfo { + name: String::from("AmbientAirTemperature"), + id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), + endpoint_info_list + }; + + let mut entity_access_info_list = Vec::new(); + entity_access_info_list.push(entity_access_info); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; @@ -116,9 +134,11 @@ async fn main() -> Result<(), Box> { 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 { dtdl }); + let request = tonic::Request::new(RegisterRequest { + entity_access_info_list + }); let _response = client.register(request).await?; - info!("The Provider's DTDL has been registered."); + debug!("The Provider's DTDL has been registered."); start_ambient_air_temperature_data_stream(subscription_map.clone()); From ecacf098ba19b60fde1aadc81f4946e5b5b15776 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 8 May 2023 15:33:50 -0700 Subject: [PATCH 04/41] Make protocol agnostic --- .../src/digitaltwin_impl.rs | 67 +++++++----- in-vehicle-digital-twin/src/main.rs | 10 +- samples/command/consumer/src/consumer_impl.rs | 4 +- samples/command/consumer/src/main.rs | 12 +-- .../dtdl/content/show_notification.json | 31 ------ samples/command/provider/src/main.rs | 10 +- samples/command/provider/src/provider_impl.rs | 5 +- samples/mixed/consumer/src/consumer_impl.rs | 4 +- samples/mixed/consumer/src/main.rs | 10 +- samples/mixed/dtdl/content/mixed.json | 100 ------------------ samples/mixed/provider/src/main.rs | 39 ++++--- samples/mixed/provider/src/provider_impl.rs | 4 +- .../property/consumer/src/consumer_impl.rs | 4 +- samples/property/consumer/src/main.rs | 6 +- .../dtdl/content/ambient_air_temperature.json | 28 ----- samples/property/provider/src/main.rs | 14 ++- .../property/provider/src/provider_impl.rs | 5 +- 17 files changed, 104 insertions(+), 249 deletions(-) delete mode 100644 samples/command/dtdl/content/show_notification.json delete mode 100644 samples/mixed/dtdl/content/mixed.json delete mode 100644 samples/property/dtdl/content/ambient_air_temperature.json diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 4fbf4e3f..3386fee1 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -9,9 +9,9 @@ use log::{debug, info, log_enabled, warn}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use proto::digitaltwin::digital_twin_server::DigitalTwin; use proto::digitaltwin::{ - EntityAccessInfo, - FindByIdRequest, FindByIdResponse, RegisterRequest, RegisterResponse, UnregisterRequest, - UnregisterResponse}; + EntityAccessInfo, FindByIdRequest, FindByIdResponse, RegisterRequest, RegisterResponse, + UnregisterRequest, UnregisterResponse, +}; use std::collections::HashMap; use std::sync::Arc; use tonic::{Request, Response, Status}; @@ -31,7 +31,7 @@ impl DigitalTwin for DigitalTwinImpl { &self, request: Request, ) -> Result, Status> { - let request_inner = request.into_inner(); + let request_inner = request.into_inner(); let entity_id = request_inner.id; @@ -41,8 +41,9 @@ impl DigitalTwin for DigitalTwinImpl { // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = self.entity_access_info_map.read(); - entity_access_info = lock.get(&entity_id).map(|value| value.clone()); + let lock: RwLockReadGuard> = + self.entity_access_info_map.read(); + entity_access_info = lock.get(&entity_id).map(|value| value.clone()); } info!("{:?}", entity_access_info); @@ -68,10 +69,10 @@ impl DigitalTwin for DigitalTwinImpl { info!("Received a register request for the the entity:\n{}", &entity_access_info.id); match self.register_entity(entity_access_info.clone()) { - Ok(_) => { - self.register_entity(entity_access_info.clone()).map_err(|error| return Status::internal(format!("{}", error)))? - }, - Err(error) => return Err(Status::internal(error)) + Ok(_) => self + .register_entity(entity_access_info.clone()) + .map_err(|error| return Status::internal(format!("{}", error)))?, + Err(error) => return Err(Status::internal(error)), }; } @@ -97,7 +98,6 @@ impl DigitalTwin for DigitalTwinImpl { } impl DigitalTwinImpl { - /// Register the entity. /// /// # Arguments @@ -105,11 +105,12 @@ impl DigitalTwinImpl { fn register_entity(&self, entity_access_info: EntityAccessInfo) -> Result<(), String> { // This block controls the lifetime of the lock. { - let mut lock: RwLockWriteGuard> = self.entity_access_info_map.write(); + let mut lock: RwLockWriteGuard> = + self.entity_access_info_map.write(); match lock.get(&entity_access_info.id) { Some(_) => { // TODO: merge existing contents with new contents - }, + } None => { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } @@ -136,7 +137,7 @@ mod digitaltwin_impl_tests { let mut operations = Vec::new(); operations.push(String::from("Subscribe")); - operations.push(String::from("Unsubscribe")); + operations.push(String::from("Unsubscribe")); let endpoint_info = EndpointInfo { protocol: String::from("grpc"), @@ -148,24 +149,28 @@ mod digitaltwin_impl_tests { let mut endpoint_info_list = Vec::new(); endpoint_info_list.push(endpoint_info); - let entity_access_info= EntityAccessInfo { + 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 - }; + endpoint_info_list, + }; 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 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(); + 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 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(); @@ -173,7 +178,10 @@ mod digitaltwin_impl_tests { assert!(response_inner.entity_access_info.is_some()); - assert!(response_inner.entity_access_info.unwrap().id == "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"); + assert!( + response_inner.entity_access_info.unwrap().id + == "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" + ); // TODO: add check } @@ -184,12 +192,12 @@ mod digitaltwin_impl_tests { let mut operations = Vec::new(); operations.push(String::from("Subscribe")); - operations.push(String::from("Unsubscribe")); + operations.push(String::from("Unsubscribe")); let endpoint_info = EndpointInfo { protocol: String::from("grpc"), uri: String::from("http://[::1]:40010"), - context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), + context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; @@ -200,19 +208,21 @@ mod digitaltwin_impl_tests { name: String::from("AmbientAirTemperature"), id: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), description: String::from("Ambient air temperature"), - endpoint_info_list + endpoint_info_list, }; let mut entity_access_info_list = Vec::new(); - entity_access_info_list.push(entity_access_info.clone()); + entity_access_info_list.push(entity_access_info.clone()); 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 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(); + let mut lock: RwLockWriteGuard> = + entity_access_info_map.write(); lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } @@ -222,7 +232,8 @@ mod digitaltwin_impl_tests { // This block controls the lifetime of the lock. { - let lock: RwLockReadGuard> = entity_access_info_map.read(); + let lock: RwLockReadGuard> = + entity_access_info_map.read(); // Make sure that we populated the entity map from the contents of the DTDL. assert!(lock.len() == 1, "expected length was 1, actual length is {}", lock.len()); } diff --git a/in-vehicle-digital-twin/src/main.rs b/in-vehicle-digital-twin/src/main.rs index 7ecc5e8f..2455836c 100644 --- a/in-vehicle-digital-twin/src/main.rs +++ b/in-vehicle-digital-twin/src/main.rs @@ -24,11 +24,11 @@ async fn main() -> Result<(), Box> { // Setup the HTTP server. let addr: SocketAddr = IN_VEHICLE_DIGITAL_TWIN_ADDR.parse()?; - let digitaltwin_impl = - digitaltwin_impl::DigitalTwinImpl { entity_access_info_map: Arc::new(RwLock::new(HashMap::new())) }; - let server_future = Server::builder() - .add_service(DigitalTwinServer::new(digitaltwin_impl)) - .serve(addr); + let digitaltwin_impl = digitaltwin_impl::DigitalTwinImpl { + entity_access_info_map: Arc::new(RwLock::new(HashMap::new())), + }; + 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_future.await?; diff --git a/samples/command/consumer/src/consumer_impl.rs b/samples/command/consumer/src/consumer_impl.rs index 05e842e1..2577fbb8 100644 --- a/samples/command/consumer/src/consumer_impl.rs +++ b/samples/command/consumer/src/consumer_impl.rs @@ -4,7 +4,9 @@ use log::{info, warn}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; -use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{ + PublishRequest, PublishResponse, RespondRequest, RespondResponse, +}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 1e545b03..d6f0fe18 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -7,9 +7,9 @@ mod consumer_impl; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; use std::net::SocketAddr; @@ -85,21 +85,21 @@ async fn main() -> Result<(), Box> { sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; let request = tonic::Request::new(FindByIdRequest { - id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) + id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }); let response = client.find_by_id(request).await?; let response_inner = response.into_inner(); debug!("Received the response for the find_by_id request"); - info!("response_payload: {:?}", response_inner.entity_access_info); - + info!("response_payload: {:?}", response_inner.entity_access_info); + let provider_uri; match response_inner.entity_access_info { Some(content) => { // TODO: select the right one, rather than just using the first one provider_uri = content.endpoint_info_list[0].uri.clone(); - }, + } None => { - panic!("Did not find an entity for the ShowNotification command"); + panic!("Did not find an entity for the ShowNotification command"); } } diff --git a/samples/command/dtdl/content/show_notification.json b/samples/command/dtdl/content/show_notification.json deleted file mode 100644 index e11e1f7e..00000000 --- a/samples/command/dtdl/content/show_notification.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI;1", - "description": "The Human Machine Interface.", - "contents": [ - { - "@type": ["Command", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI:ShowNotification;1", - "name": "ShowNotification", - "request": { - "name": "ShowNotification", - "displayName": "Show Notification", - "descriptiption": "Show a notification on the HMI.", - "schema": "string" - }, - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Invoke" ] - } - ] - } - ] - } -] \ No newline at end of file diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 76ae94cc..c04f8416 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 proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; +use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; @@ -36,7 +36,7 @@ async fn main() -> Result<(), Box> { protocol: String::from("grpc"), operations, uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) + context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; let mut endpoint_info_list = Vec::new(); @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoint_info_list + endpoint_info_list, }; let mut entity_access_info_list = Vec::new(); @@ -62,9 +62,7 @@ async fn main() -> Result<(), Box> { 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 - }); + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); let _response = client.register(request).await?; debug!("The Provider's DTDL has been registered."); diff --git a/samples/command/provider/src/provider_impl.rs b/samples/command/provider/src/provider_impl.rs index 802bbbb5..79833594 100644 --- a/samples/command/provider/src/provider_impl.rs +++ b/samples/command/provider/src/provider_impl.rs @@ -7,8 +7,9 @@ use parking_lot::Mutex; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::RespondRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProvider; -use samples_proto::sample_grpc::v1::digital_twin_provider::{ GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, - SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, +use samples_proto::sample_grpc::v1::digital_twin_provider::{ + GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, + SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; use std::sync::Arc; diff --git a/samples/mixed/consumer/src/consumer_impl.rs b/samples/mixed/consumer/src/consumer_impl.rs index 306471fa..2a8b457f 100644 --- a/samples/mixed/consumer/src/consumer_impl.rs +++ b/samples/mixed/consumer/src/consumer_impl.rs @@ -4,7 +4,9 @@ use log::info; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; -use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{ + PublishRequest, PublishResponse, RespondRequest, RespondResponse, +}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index b3899570..07fde4b0 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -7,11 +7,13 @@ mod consumer_impl; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; -use samples_proto::sample_grpc::v1::digital_twin_provider::{InvokeRequest, SetRequest, SubscribeRequest}; +use samples_proto::sample_grpc::v1::digital_twin_provider::{ + InvokeRequest, SetRequest, SubscribeRequest, +}; use std::net::SocketAddr; use tokio::time::{sleep, Duration}; use tonic::transport::Server; @@ -124,9 +126,9 @@ async fn get_provider_uri(entity_id: &str) -> Result { Some(content) => { // TODO: select the right one, rather than just using the first one provider_uri = content.endpoint_info_list[0].uri.clone(); - }, + } None => { - panic!("Did not find an entity for the AmbientAirTemperature command"); + panic!("Did not find an entity for the AmbientAirTemperature command"); } } diff --git a/samples/mixed/dtdl/content/mixed.json b/samples/mixed/dtdl/content/mixed.json deleted file mode 100644 index 5a6781bd..00000000 --- a/samples/mixed/dtdl/content/mixed.json +++ /dev/null @@ -1,100 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:Cabin:HVAC;1", - "description": "Heat, Ventilation and Air Conditioning", - "contents": [ - { - "@type": ["Property", "Temperature", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1", - "name": "AmbientAirTemperature", - "description": "The immediate surroundings air temperature (in Fahrenheit).", - "schema": "integer", - "unit": "degreeFahrenheit", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Subscribe", "Unsubscribe" ] - } - ] - }, - { - "@type": ["Property", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:IsAirConditioningActive;1", - "name": "IsAirConditioningActive", - "description": "Is air conditioning active?", - "schema": "boolean", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Set", "Subscribe", "Unsubscribe" ] - } - ] - } - ] - }, - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:OBD;1", - "description": "On-board Diagnostics Interface", - "contents": [ - { - "@type": ["Property", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:OBD:HybridBatteryRemaining;1", - "name": "HybridBatteryRemaining", - "description": "The remaining hybrid battery life.", - "schema": "integer", - "unit": "percent", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Subscribe", "Unsubscribe" ] - } - ] - } - ] - }, - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI;1", - "description": "The Human Machine Interface.", - "contents": [ - { - "@type": ["Command", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:Cabin:Infotainment:HMI:ShowNotification;1", - "name": "ShowNotification", - "request": { - "name": "ShowNotification", - "displayName": "Show Notification", - "descriptiption": "Show a notification on the HMI.", - "schema": "string" - }, - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Invoke" ] - } - ] - } - ] - } -] \ No newline at end of file diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 1565e949..6db73e91 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -9,10 +9,10 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; +use proto::digitaltwin::digital_twin_client::DigitalTwinClient; +use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; @@ -130,18 +130,17 @@ async fn main() -> Result<(), Box> { let mut property_operations = Vec::new(); property_operations.push(String::from("Subscribe")); property_operations.push(String::from("Unsubscribe")); - property_operations.push(String::from("Get")); - property_operations.push(String::from("Set")); + property_operations.push(String::from("Set")); let mut command_operations = Vec::new(); - command_operations.push(String::from("Invoke")); + command_operations.push(String::from("Invoke")); // AmbientAirTemperature let ambient_air_temperature_endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: telemetry_operations.clone(), uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut ambient_air_temperature_endpoint_info_list = Vec::new(); ambient_air_temperature_endpoint_info_list.push(ambient_air_temperature_endpoint_info); @@ -149,7 +148,7 @@ async fn main() -> Result<(), Box> { name: String::from("AmbientAirTemperature"), id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), - endpoint_info_list: ambient_air_temperature_endpoint_info_list + endpoint_info_list: ambient_air_temperature_endpoint_info_list, }; // IsAirConditioningActive @@ -157,15 +156,15 @@ async fn main() -> Result<(), Box> { protocol: String::from("grpc"), operations: property_operations, uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut is_air_conditioning_active_endpoint_info_list = Vec::new(); - is_air_conditioning_active_endpoint_info_list.push(is_air_conditioning_active_endpoint_info); + is_air_conditioning_active_endpoint_info_list.push(is_air_conditioning_active_endpoint_info); let is_air_conditioning_active_access_info = EntityAccessInfo { name: String::from("IsAirConditioningActive"), id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), description: String::from("Is air conditioning active?"), - endpoint_info_list: is_air_conditioning_active_endpoint_info_list + endpoint_info_list: is_air_conditioning_active_endpoint_info_list, }; // HybridBatteryRemaining @@ -173,7 +172,7 @@ async fn main() -> Result<(), Box> { protocol: String::from("grpc"), operations: telemetry_operations, uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID) + context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), }; let mut hybrid_battery_remaining_endpoint_info_list = Vec::new(); hybrid_battery_remaining_endpoint_info_list.push(hybrid_battery_remaining_endpoint_info); @@ -181,7 +180,7 @@ async fn main() -> Result<(), Box> { name: String::from("HybridBatteryRemaining"), id: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), description: String::from("The remaining hybrid battery life."), - endpoint_info_list: hybrid_battery_remaining_endpoint_info_list + endpoint_info_list: hybrid_battery_remaining_endpoint_info_list, }; // ShowNotification @@ -189,22 +188,22 @@ async fn main() -> Result<(), Box> { protocol: String::from("grpc"), operations: command_operations, uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) - }; + context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + }; let mut show_notification_endpoint_info_list = Vec::new(); - show_notification_endpoint_info_list.push(show_notification_endpoint_info); + show_notification_endpoint_info_list.push(show_notification_endpoint_info); let show_notification_access_info = EntityAccessInfo { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoint_info_list: show_notification_endpoint_info_list + endpoint_info_list: show_notification_endpoint_info_list, }; let mut entity_access_info_list = Vec::new(); entity_access_info_list.push(ambient_air_temperature_access_info); entity_access_info_list.push(is_air_conditioning_active_access_info); entity_access_info_list.push(hybrid_battery_remaining_access_info); - entity_access_info_list.push(show_notification_access_info); + entity_access_info_list.push(show_notification_access_info); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; @@ -218,11 +217,9 @@ async fn main() -> Result<(), Box> { 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 - }); + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); let _response = client.register(request).await?; - debug!("The Provider's DTDL has been registered."); + debug!("The Provider's DTDL has been registered."); start_vehicle_simulator(subscription_map.clone(), vehicle).await; diff --git a/samples/mixed/provider/src/provider_impl.rs b/samples/mixed/provider/src/provider_impl.rs index 0dc72715..cd134dd9 100644 --- a/samples/mixed/provider/src/provider_impl.rs +++ b/samples/mixed/provider/src/provider_impl.rs @@ -9,8 +9,8 @@ use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer use samples_proto::sample_grpc::v1::digital_twin_consumer::RespondRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProvider; use samples_proto::sample_grpc::v1::digital_twin_provider::{ - GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, - SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, + GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, SetResponse, + SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; use std::str::FromStr; diff --git a/samples/property/consumer/src/consumer_impl.rs b/samples/property/consumer/src/consumer_impl.rs index 6675d77d..c06f31f7 100644 --- a/samples/property/consumer/src/consumer_impl.rs +++ b/samples/property/consumer/src/consumer_impl.rs @@ -4,7 +4,9 @@ use log::{info, warn}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumer; -use samples_proto::sample_grpc::v1::digital_twin_consumer::{PublishRequest, PublishResponse, RespondRequest, RespondResponse}; +use samples_proto::sample_grpc::v1::digital_twin_consumer::{ + PublishRequest, PublishResponse, RespondRequest, RespondResponse, +}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index dfb1589b..7a86246d 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -5,9 +5,9 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use proto::digitaltwin::digital_twin_client::DigitalTwinClient; use proto::digitaltwin::FindByIdRequest; +use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; use std::net::SocketAddr; @@ -49,9 +49,9 @@ async fn main() -> Result<(), Box> { Some(content) => { // TODO: select the right one, rather than just using the first one provider_uri = content.endpoint_info_list[0].uri.clone(); - }, + } None => { - panic!("Did not find an entity for the AmbientAirTemperature command"); + panic!("Did not find an entity for the AmbientAirTemperature command"); } } diff --git a/samples/property/dtdl/content/ambient_air_temperature.json b/samples/property/dtdl/content/ambient_air_temperature.json deleted file mode 100644 index 6f5b06b4..00000000 --- a/samples/property/dtdl/content/ambient_air_temperature.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;2"], - "@type": "Interface", - "@id": "dtmi:sdv:Vehicle:Cabin:HVAC;1", - "description": "Heat, Ventilation and Air Conditioning", - "contents": [ - { - "@type": ["Property", "Temperature", "RemotelyAccessible"], - "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1", - "name": "ambient_air_temperature", - "description": "The immediate surroundings air temperature (in Fahrenheit).", - "schema": "integer", - "unit": "degreeFahrenheit", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "communication_protocol": "http", - "schema_kind": "grpc", - "schema_reference": "https://github.com/eclipse-ibeji/samples/proto/sample_grpc/v1/digital_twin_provider.proto", - "operations": [ "Subscribe", "Unsubscribe" ] - } - ] - } - ] - } -] \ No newline at end of file diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index a20a51b7..86e5b1b7 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -8,10 +8,10 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; +use proto::digitaltwin::digital_twin_client::DigitalTwinClient; +use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{RegisterRequest, EndpointInfo, EntityAccessInfo}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::collections::HashSet; use std::net::SocketAddr; @@ -108,7 +108,7 @@ async fn main() -> Result<(), Box> { protocol: String::from("grpc"), operations, uri: String::from("http://[::1]:40010"), - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID) + context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut endpoint_info_list = Vec::new(); @@ -118,7 +118,7 @@ async fn main() -> Result<(), Box> { name: String::from("AmbientAirTemperature"), id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), - endpoint_info_list + endpoint_info_list, }; let mut entity_access_info_list = Vec::new(); @@ -134,11 +134,9 @@ async fn main() -> Result<(), Box> { 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 - }); + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); let _response = client.register(request).await?; - debug!("The Provider's DTDL has been registered."); + debug!("The Provider's DTDL has been registered."); start_ambient_air_temperature_data_stream(subscription_map.clone()); diff --git a/samples/property/provider/src/provider_impl.rs b/samples/property/provider/src/provider_impl.rs index 4ad14b1f..6bc8e1eb 100644 --- a/samples/property/provider/src/provider_impl.rs +++ b/samples/property/provider/src/provider_impl.rs @@ -5,8 +5,9 @@ use log::{debug, info, warn}; use parking_lot::{Mutex, MutexGuard}; use samples_proto::sample_grpc::v1::digital_twin_provider::{ - digital_twin_provider_server::DigitalTwinProvider, GetRequest, GetResponse, InvokeRequest, InvokeResponse, SetRequest, - SetResponse, SubscribeRequest, SubscribeResponse, UnsubscribeRequest, UnsubscribeResponse, + digital_twin_provider_server::DigitalTwinProvider, GetRequest, GetResponse, InvokeRequest, + InvokeResponse, SetRequest, SetResponse, SubscribeRequest, SubscribeResponse, + UnsubscribeRequest, UnsubscribeResponse, }; use std::collections::{HashMap, HashSet}; use std::sync::Arc; From 98b87f5f3ee65ca058dc93f11b7318404b7f8bbe Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 8 May 2023 16:25:44 -0700 Subject: [PATCH 05/41] Make protocol agnostic --- Cargo.toml | 2 +- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 4 ++-- proto/digitaltwin.proto | 6 +++--- samples/command/provider/src/main.rs | 2 +- samples/mixed/provider/src/main.rs | 8 ++++---- samples/property/provider/src/main.rs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ff7db804..6250dd4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ "common", "common-test", - "dt-model/dt-model-identifiers", + "dt-model/dt-model-identifiers", "dtdl-parser", "in-vehicle-digital-twin", "samples/proto", diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 3386fee1..8d5cea7d 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -141,7 +141,7 @@ mod digitaltwin_impl_tests { let endpoint_info = EndpointInfo { protocol: String::from("grpc"), - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; @@ -196,7 +196,7 @@ mod digitaltwin_impl_tests { let endpoint_info = EndpointInfo { protocol: String::from("grpc"), - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; diff --git a/proto/digitaltwin.proto b/proto/digitaltwin.proto index 9a77b9bd..0f44b318 100644 --- a/proto/digitaltwin.proto +++ b/proto/digitaltwin.proto @@ -19,12 +19,12 @@ message EndpointInfo { string context = 4; } -message EntityAccessInfo { +message EntityAccessInfo { string name = 1; string id = 2; string description = 3; repeated EndpointInfo endpointInfoList = 4; -} +} message FindByIdRequest { string id = 1; @@ -45,7 +45,7 @@ message UnregisterRequest { string id = 1; string protocol = 2; string uri = 3; - string context = 4; + string context = 4; } message UnregisterResponse { diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index c04f8416..1ef0724a 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -35,7 +35,7 @@ async fn main() -> Result<(), Box> { let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations, - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 6db73e91..4b773836 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -139,7 +139,7 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: telemetry_operations.clone(), - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut ambient_air_temperature_endpoint_info_list = Vec::new(); @@ -155,7 +155,7 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: property_operations, - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut is_air_conditioning_active_endpoint_info_list = Vec::new(); @@ -171,7 +171,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: telemetry_operations, - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), }; let mut hybrid_battery_remaining_endpoint_info_list = Vec::new(); @@ -187,7 +187,7 @@ async fn main() -> Result<(), Box> { let show_notification_endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: command_operations, - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; let mut show_notification_endpoint_info_list = Vec::new(); diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 86e5b1b7..e878186d 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -107,7 +107,7 @@ async fn main() -> Result<(), Box> { let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations, - uri: String::from("http://[::1]:40010"), + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; From 34f0401b2dbb9712da0d3c20c56bf42fe3e0cd01 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 11:46:09 -0700 Subject: [PATCH 06/41] Make protocol agnostic --- .../src/digitaltwin_impl.rs | 12 +++--- samples/command/provider/src/main.rs | 19 +++----- samples/mixed/provider/src/main.rs | 43 ++++++++----------- samples/property/provider/src/main.rs | 13 ++---- 4 files changed, 31 insertions(+), 56 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 8d5cea7d..82688aac 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -43,7 +43,7 @@ impl DigitalTwin for DigitalTwinImpl { { let lock: RwLockReadGuard> = self.entity_access_info_map.read(); - entity_access_info = lock.get(&entity_id).map(|value| value.clone()); + entity_access_info = lock.get(&entity_id).cloned(); } info!("{:?}", entity_access_info); @@ -71,7 +71,7 @@ impl DigitalTwin for DigitalTwinImpl { match self.register_entity(entity_access_info.clone()) { Ok(_) => self .register_entity(entity_access_info.clone()) - .map_err(|error| return Status::internal(format!("{}", error)))?, + .map_err(|error| Status::internal(format!("{}", error)))?, Err(error) => return Err(Status::internal(error)), }; } @@ -135,13 +135,11 @@ mod digitaltwin_impl_tests { async fn find_by_id_test() { set_dtdl_path(); - let mut operations = Vec::new(); - operations.push(String::from("Subscribe")); - operations.push(String::from("Unsubscribe")); + 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 + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; @@ -196,7 +194,7 @@ mod digitaltwin_impl_tests { let endpoint_info = EndpointInfo { protocol: String::from("grpc"), - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from("dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1"), operations, }; diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 1ef0724a..decd2fad 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -28,30 +28,20 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let mut operations = Vec::new(); - operations.push(String::from("Get")); - operations.push(String::from("Set")); - let endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations, - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![String::from("Get"), String::from("Set")], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; - let mut endpoint_info_list = Vec::new(); - endpoint_info_list.push(endpoint_info); - let entity_access_info = EntityAccessInfo { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoint_info_list, + endpoint_info_list: vec![endpoint_info], }; - let mut entity_access_info_list = Vec::new(); - entity_access_info_list.push(entity_access_info); - // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); @@ -62,7 +52,8 @@ async fn main() -> Result<(), Box> { 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 }); + 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."); diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 4b773836..5df2a154 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -123,23 +123,11 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let mut telemetry_operations = Vec::new(); - telemetry_operations.push(String::from("Subscribe")); - telemetry_operations.push(String::from("Unsubscribe")); - - let mut property_operations = Vec::new(); - property_operations.push(String::from("Subscribe")); - property_operations.push(String::from("Unsubscribe")); - property_operations.push(String::from("Set")); - - let mut command_operations = Vec::new(); - command_operations.push(String::from("Invoke")); - // AmbientAirTemperature let ambient_air_temperature_endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations: telemetry_operations.clone(), - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut ambient_air_temperature_endpoint_info_list = Vec::new(); @@ -154,8 +142,12 @@ async fn main() -> Result<(), Box> { // IsAirConditioningActive let is_air_conditioning_active_endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations: property_operations, - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![ + String::from("Subscribe"), + String::from("Unsubscribe"), + String::from("Get"), + ], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; let mut is_air_conditioning_active_endpoint_info_list = Vec::new(); @@ -170,8 +162,8 @@ async fn main() -> Result<(), Box> { // HybridBatteryRemaining let hybrid_battery_remaining_endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations: telemetry_operations, - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), }; let mut hybrid_battery_remaining_endpoint_info_list = Vec::new(); @@ -186,8 +178,8 @@ async fn main() -> Result<(), Box> { // ShowNotification let show_notification_endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations: command_operations, - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![String::from("Invoke")], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; let mut show_notification_endpoint_info_list = Vec::new(); @@ -199,11 +191,12 @@ async fn main() -> Result<(), Box> { endpoint_info_list: show_notification_endpoint_info_list, }; - let mut entity_access_info_list = Vec::new(); - entity_access_info_list.push(ambient_air_temperature_access_info); - entity_access_info_list.push(is_air_conditioning_active_access_info); - entity_access_info_list.push(hybrid_battery_remaining_access_info); - entity_access_info_list.push(show_notification_access_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, + ]; // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index e878186d..16c08a69 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -100,25 +100,18 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - let mut operations = Vec::new(); - operations.push(String::from("Subscribe")); - operations.push(String::from("Unsubscribe")); - let endpoint_info = EndpointInfo { protocol: String::from("grpc"), - operations, - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 + operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], + uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; - let mut endpoint_info_list = Vec::new(); - endpoint_info_list.push(endpoint_info); - let entity_access_info = EntityAccessInfo { name: String::from("AmbientAirTemperature"), id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), - endpoint_info_list, + endpoint_info_list: vec![endpoint_info], }; let mut entity_access_info_list = Vec::new(); From 455ca81ae6c3baae7fbc36dfce1d540725ed0059 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:22:55 -0700 Subject: [PATCH 07/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 82688aac..07473cb0 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -71,7 +71,7 @@ impl DigitalTwin for DigitalTwinImpl { match self.register_entity(entity_access_info.clone()) { Ok(_) => self .register_entity(entity_access_info.clone()) - .map_err(|error| Status::internal(format!("{}", error)))?, + .map_err(|error| Status::internal(format!("{error}")))?, Err(error) => return Err(Status::internal(error)), }; } @@ -144,14 +144,11 @@ mod digitaltwin_impl_tests { operations, }; - let mut endpoint_info_list = Vec::new(); - endpoint_info_list.push(endpoint_info); - 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, + endpoint_info_list: vec![endpoint_info], }; let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); @@ -188,15 +185,11 @@ mod digitaltwin_impl_tests { async fn register_test() { set_dtdl_path(); - let mut operations = Vec::new(); - operations.push(String::from("Subscribe")); - operations.push(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, + operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], }; let mut endpoint_info_list = Vec::new(); From a8cd1608d7c925929b6a7f50ab30e90ed2edfe0a Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:29:05 -0700 Subject: [PATCH 08/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 07473cb0..36605a58 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -71,7 +71,7 @@ impl DigitalTwin for DigitalTwinImpl { match self.register_entity(entity_access_info.clone()) { Ok(_) => self .register_entity(entity_access_info.clone()) - .map_err(|error| Status::internal(format!("{error}")))?, + .map_err(|error| Status::internal(error))?, Err(error) => return Err(Status::internal(error)), }; } From d3d15a1678cf05fa43d0124c5013896bb91ffa84 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:38:19 -0700 Subject: [PATCH 09/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 36605a58..4d360e26 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -71,7 +71,7 @@ impl DigitalTwin for DigitalTwinImpl { match self.register_entity(entity_access_info.clone()) { Ok(_) => self .register_entity(entity_access_info.clone()) - .map_err(|error| Status::internal(error))?, + .map_err(Status::internal)?, Err(error) => return Err(Status::internal(error)), }; } @@ -192,19 +192,13 @@ mod digitaltwin_impl_tests { operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], }; - let mut endpoint_info_list = Vec::new(); - endpoint_info_list.push(endpoint_info); - 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, + endpoint_info_list: vec!(endpoint_info), }; - let mut entity_access_info_list = Vec::new(); - entity_access_info_list.push(entity_access_info.clone()); - let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); let digital_twin_impl = @@ -217,7 +211,7 @@ mod digitaltwin_impl_tests { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } - let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); + 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()); From 2b52f92c6f5259774f7c2bab028fc5a6067838b3 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:43:45 -0700 Subject: [PATCH 10/41] Make protocol agnostic --- samples/property/provider/src/main.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 16c08a69..826fb789 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -114,9 +114,6 @@ async fn main() -> Result<(), Box> { endpoint_info_list: vec![endpoint_info], }; - let mut entity_access_info_list = Vec::new(); - entity_access_info_list.push(entity_access_info); - // Setup the HTTP server. let addr: SocketAddr = PROVIDER_ADDR.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); @@ -127,7 +124,7 @@ async fn main() -> Result<(), Box> { 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 }); + 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."); From 89a263f8fa1cfe0bac457ff98f203e5450211a94 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:50:30 -0700 Subject: [PATCH 11/41] Make protocol agnostic --- samples/command/consumer/src/main.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index d6f0fe18..2ad55e1a 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -92,16 +92,15 @@ async fn main() -> Result<(), Box> { debug!("Received the response for the find_by_id request"); info!("response_payload: {:?}", response_inner.entity_access_info); - let provider_uri; - match response_inner.entity_access_info { + let provider_uri = match response_inner.entity_access_info { Some(content) => { // TODO: select the right one, rather than just using the first one - provider_uri = content.endpoint_info_list[0].uri.clone(); - } + content.endpoint_info_list[0].uri.clone() + }, None => { panic!("Did not find an entity for the ShowNotification command"); } - } + }; info!("The URI for the show-notification command's provider is {provider_uri}"); From ce0e66eb808007c0d30810bd59d4680c8d23ce97 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 14:52:56 -0700 Subject: [PATCH 12/41] Make protocol agnostic --- samples/mixed/consumer/src/main.rs | 9 ++++----- samples/property/consumer/src/main.rs | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 07fde4b0..3ecb831d 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -121,16 +121,15 @@ async fn get_provider_uri(entity_id: &str) -> Result { debug!("Received the response for the find_by_id request"); info!("response_payload: {:?}", response_inner.entity_access_info); - let provider_uri; - match response_inner.entity_access_info { + let provider_uri = match response_inner.entity_access_info { Some(content) => { // TODO: select the right one, rather than just using the first one - provider_uri = content.endpoint_info_list[0].uri.clone(); - } + content.endpoint_info_list[0].uri.clone() + }, None => { panic!("Did not find an entity for the AmbientAirTemperature command"); } - } + }; info!("The provider URI for entity id {entity_id} is {provider_uri}"); diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 7a86246d..2d8533a5 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -44,16 +44,15 @@ async fn main() -> Result<(), Box> { debug!("Received the response for the find_by_id request"); info!("response_payload: {:?}", response_inner.entity_access_info); - let provider_uri; - match response_inner.entity_access_info { + let provider_uri = match response_inner.entity_access_info { Some(content) => { // TODO: select the right one, rather than just using the first one - provider_uri = content.endpoint_info_list[0].uri.clone(); - } + content.endpoint_info_list[0].uri.clone() + }, None => { panic!("Did not find an entity for the AmbientAirTemperature command"); } - } + }; let consumer_uri = format!("http://{CONSUMER_ADDR}"); // Devskim: ignore DS137138 From 7ec3a343aba1596c12ec2f4d40841d1c3cdaa34f Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 15:01:44 -0700 Subject: [PATCH 13/41] Make protocol agnostic --- samples/mixed/provider/src/main.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 5df2a154..3f400924 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -130,13 +130,11 @@ async fn main() -> Result<(), Box> { uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; - let mut ambient_air_temperature_endpoint_info_list = Vec::new(); - ambient_air_temperature_endpoint_info_list.push(ambient_air_temperature_endpoint_info); let ambient_air_temperature_access_info = EntityAccessInfo { name: String::from("AmbientAirTemperature"), id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), - endpoint_info_list: ambient_air_temperature_endpoint_info_list, + endpoint_info_list: vec!(ambient_air_temperature_endpoint_info), }; // IsAirConditioningActive @@ -150,13 +148,11 @@ async fn main() -> Result<(), Box> { uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), }; - let mut is_air_conditioning_active_endpoint_info_list = Vec::new(); - is_air_conditioning_active_endpoint_info_list.push(is_air_conditioning_active_endpoint_info); let is_air_conditioning_active_access_info = EntityAccessInfo { name: String::from("IsAirConditioningActive"), id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), description: String::from("Is air conditioning active?"), - endpoint_info_list: is_air_conditioning_active_endpoint_info_list, + endpoint_info_list: vec!(is_air_conditioning_active_endpoint_info), }; // HybridBatteryRemaining @@ -166,13 +162,11 @@ async fn main() -> Result<(), Box> { uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), }; - let mut hybrid_battery_remaining_endpoint_info_list = Vec::new(); - hybrid_battery_remaining_endpoint_info_list.push(hybrid_battery_remaining_endpoint_info); let hybrid_battery_remaining_access_info = EntityAccessInfo { name: String::from("HybridBatteryRemaining"), id: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), description: String::from("The remaining hybrid battery life."), - endpoint_info_list: hybrid_battery_remaining_endpoint_info_list, + endpoint_info_list: vec!(hybrid_battery_remaining_endpoint_info), }; // ShowNotification @@ -182,13 +176,11 @@ async fn main() -> Result<(), Box> { uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), }; - let mut show_notification_endpoint_info_list = Vec::new(); - show_notification_endpoint_info_list.push(show_notification_endpoint_info); let show_notification_access_info = EntityAccessInfo { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoint_info_list: show_notification_endpoint_info_list, + endpoint_info_list: vec!(show_notification_endpoint_info), }; let entity_access_info_list = vec![ From b2b2c5f03bff2aa044746fb97063c2116d645708 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Tue, 9 May 2023 15:07:25 -0700 Subject: [PATCH 14/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 12 +++++++----- samples/command/consumer/src/main.rs | 2 +- samples/mixed/consumer/src/main.rs | 2 +- samples/mixed/provider/src/main.rs | 8 ++++---- samples/property/consumer/src/main.rs | 2 +- samples/property/provider/src/main.rs | 3 ++- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 4d360e26..5244db87 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -69,9 +69,9 @@ impl DigitalTwin for DigitalTwinImpl { info!("Received a register request for the the entity:\n{}", &entity_access_info.id); match self.register_entity(entity_access_info.clone()) { - Ok(_) => self - .register_entity(entity_access_info.clone()) - .map_err(Status::internal)?, + Ok(_) => { + self.register_entity(entity_access_info.clone()).map_err(Status::internal)? + } Err(error) => return Err(Status::internal(error)), }; } @@ -196,7 +196,7 @@ mod digitaltwin_impl_tests { 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), + endpoint_info_list: vec![endpoint_info], }; let entity_access_info_map = Arc::new(RwLock::new(HashMap::new())); @@ -211,7 +211,9 @@ mod digitaltwin_impl_tests { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); } - let request = tonic::Request::new(RegisterRequest { entity_access_info_list: vec!(entity_access_info) }); + 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()); diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 2ad55e1a..30777b96 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -96,7 +96,7 @@ async fn main() -> Result<(), Box> { Some(content) => { // TODO: select the right one, rather than just using the first one content.endpoint_info_list[0].uri.clone() - }, + } None => { panic!("Did not find an entity for the ShowNotification command"); } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 3ecb831d..959a25a6 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -125,7 +125,7 @@ async fn get_provider_uri(entity_id: &str) -> Result { Some(content) => { // TODO: select the right one, rather than just using the first one content.endpoint_info_list[0].uri.clone() - }, + } None => { panic!("Did not find an entity for the AmbientAirTemperature command"); } diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 3f400924..efbd5b75 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -134,7 +134,7 @@ async fn main() -> Result<(), Box> { name: String::from("AmbientAirTemperature"), id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), - endpoint_info_list: vec!(ambient_air_temperature_endpoint_info), + endpoint_info_list: vec![ambient_air_temperature_endpoint_info], }; // IsAirConditioningActive @@ -152,7 +152,7 @@ async fn main() -> Result<(), Box> { name: String::from("IsAirConditioningActive"), id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), description: String::from("Is air conditioning active?"), - endpoint_info_list: vec!(is_air_conditioning_active_endpoint_info), + endpoint_info_list: vec![is_air_conditioning_active_endpoint_info], }; // HybridBatteryRemaining @@ -166,7 +166,7 @@ async fn main() -> Result<(), Box> { name: String::from("HybridBatteryRemaining"), id: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), description: String::from("The remaining hybrid battery life."), - endpoint_info_list: vec!(hybrid_battery_remaining_endpoint_info), + endpoint_info_list: vec![hybrid_battery_remaining_endpoint_info], }; // ShowNotification @@ -180,7 +180,7 @@ async fn main() -> Result<(), Box> { name: String::from("ShowNotification"), id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), description: String::from("Show a notification on the HMI."), - endpoint_info_list: vec!(show_notification_endpoint_info), + endpoint_info_list: vec![show_notification_endpoint_info], }; let entity_access_info_list = vec![ diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 2d8533a5..98376f8c 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -48,7 +48,7 @@ async fn main() -> Result<(), Box> { Some(content) => { // TODO: select the right one, rather than just using the first one content.endpoint_info_list[0].uri.clone() - }, + } None => { panic!("Did not find an entity for the AmbientAirTemperature command"); } diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 826fb789..d60357c3 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -124,7 +124,8 @@ async fn main() -> Result<(), Box> { 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 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."); From 8c33e7bfff97e6df3a61ff274e41af65dc254bb5 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Wed, 10 May 2023 09:28:15 -0700 Subject: [PATCH 15/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 4 ++-- samples/command/consumer/src/main.rs | 9 ++++----- samples/command/provider/src/main.rs | 6 +++--- samples/command/provider/src/provider_impl.rs | 8 +++----- samples/mixed/consumer/src/main.rs | 10 +++++----- samples/mixed/provider/src/main.rs | 10 +++++----- samples/property/consumer/src/main.rs | 7 ++++--- samples/property/provider/src/main.rs | 6 +++--- 8 files changed, 29 insertions(+), 31 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 5244db87..e5079d8d 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -46,7 +46,7 @@ impl DigitalTwin for DigitalTwinImpl { entity_access_info = lock.get(&entity_id).cloned(); } - info!("{:?}", entity_access_info); + info!("{entity_access_info:?}"); let response = FindByIdResponse { entity_access_info }; @@ -66,7 +66,7 @@ impl DigitalTwin for DigitalTwinImpl { let request_inner = request.into_inner(); for entity_access_info in &request_inner.entity_access_info_list { - info!("Received a register request for the the entity:\n{}", &entity_access_info.id); + info!("Received a register request for the the entity:\n{}", entity_access_info.id); match self.register_entity(entity_access_info.clone()) { Ok(_) => { diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 30777b96..5e9ab35f 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -18,7 +18,7 @@ use tonic::transport::Server; use uuid::Uuid; const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const CONSUMER_ADDR: &str = "[::1]:60010"; +const CONSUMER_AUTHORITY: &str = "[::1]:60010"; /// Start the show notification repeater. /// @@ -74,12 +74,11 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); // Setup the HTTP server. - let consumer_authority = String::from(CONSUMER_ADDR); - 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_ADDR}'"); + info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); @@ -104,7 +103,7 @@ async fn main() -> Result<(), Box> { info!("The URI for the show-notification command's provider is {provider_uri}"); - let consumer_uri = format!("http://{CONSUMER_ADDR}"); // 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 decd2fad..2081a735 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -18,7 +18,7 @@ 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_ADDR: &str = "[::1]:40010"; +const PROVIDER_AUTHORITY: &str = "[::1]:40010"; #[tokio::main] #[allow(clippy::collapsible_else_if)] @@ -43,12 +43,12 @@ async fn main() -> Result<(), Box> { }; // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_ADDR.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_ADDR}'"); + 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?; diff --git a/samples/command/provider/src/provider_impl.rs b/samples/command/provider/src/provider_impl.rs index 79833594..6ded9258 100644 --- a/samples/command/provider/src/provider_impl.rs +++ b/samples/command/provider/src/provider_impl.rs @@ -91,11 +91,9 @@ impl DigitalTwinProvider for ProviderImpl { info!("Notification: '{payload}'"); tokio::spawn(async move { - let client_result = DigitalTwinConsumerClient::connect(consumer_uri.clone()).await; - if client_result.is_err() { - return Err(Status::internal(format!("{:?}", client_result.unwrap_err()))); - } - let mut client = client_result.unwrap(); + let mut client = DigitalTwinConsumerClient::connect(consumer_uri.clone()) + .await + .map_err(|error| Status::internal(error.to_string()))?; let respond_request = tonic::Request::new(RespondRequest { entity_id: entity_id.clone(), diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 959a25a6..77e67b42 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -21,7 +21,7 @@ use uuid::Uuid; const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const CONSUMER_ADDR: &str = "[::1]:60010"; +const CONSUMER_AUTHORITY: &str = "[::1]:60010"; /// Start the show-notification repeater. /// @@ -116,7 +116,7 @@ async fn get_provider_uri(entity_id: &str) -> Result { .await .map_err(|error| format!("{error}"))?; let request = tonic::Request::new(FindByIdRequest { id: String::from(entity_id) }); - let response = client.find_by_id(request).await.map_err(|error| format!("{error}"))?; + 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); @@ -160,11 +160,11 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); // Setup the HTTP server. - let addr: SocketAddr = CONSUMER_ADDR.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_ADDR}'"); + info!("The HTTP server is listening on address '{CONSUMER_AUTHORITY}'"); let show_notification_command_provider_uri = get_provider_uri(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) @@ -180,7 +180,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_uri = get_provider_uri(sdv::vehicle::obd::hybrid_battery_remaining::ID).await.unwrap(); - let consumer_uri = format!("http://{CONSUMER_ADDR}"); // Devskim: ignore DS137138 + let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 send_subscribe_request( &ambient_air_temperature_property_provider_uri, diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index efbd5b75..f7e59dbf 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -24,7 +24,7 @@ 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_ADDR: &str = "[::1]:40010"; +const PROVIDER_AUTHORITY: &str = "[::1]:40010"; async fn publish(subscription_map: Arc>, entity_id: &str, value: &str) { let urls; @@ -191,20 +191,20 @@ async fn main() -> Result<(), Box> { ]; // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_ADDR.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_ADDR}'"); + 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}"); + 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 DTDL has been registered."); + debug!("The Provider's entity access info has been registered."); 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 98376f8c..056e04d7 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -17,7 +17,7 @@ mod consumer_impl; const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 -const CONSUMER_ADDR: &str = "[::1]:60010"; +const CONSUMER_AUTHORITY: &str = "[::1]:60010"; #[tokio::main] async fn main() -> Result<(), Box> { @@ -27,10 +27,11 @@ async fn main() -> Result<(), Box> { info!("The Consumer has started."); // Setup the HTTP server. - let addr: SocketAddr = CONSUMER_ADDR.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}'"); // Obtain the DTDL for the ambient air temmpterature. info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", @@ -54,7 +55,7 @@ async fn main() -> Result<(), Box> { } }; - let consumer_uri = format!("http://{CONSUMER_ADDR}"); // 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 d60357c3..2e2e8785 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -22,7 +22,7 @@ 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_ADDR: &str = "[::1]:40010"; +const PROVIDER_AUTHORITY: &str = "[::1]:40010"; /// Start the ambient air temperature data stream. /// @@ -115,12 +115,12 @@ async fn main() -> Result<(), Box> { }; // Setup the HTTP server. - let addr: SocketAddr = PROVIDER_ADDR.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_ADDR}'"); + 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?; From 15d84cad0ae25be4e40e598419f8d899298fe6fa Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Wed, 10 May 2023 10:28:51 -0700 Subject: [PATCH 16/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 6 +++--- in-vehicle-digital-twin/src/main.rs | 2 +- proto/build.rs | 2 +- .../v1/digital_twin.proto} | 2 +- proto/src/lib.rs | 4 ++-- samples/command/consumer/src/main.rs | 4 ++-- samples/command/provider/src/main.rs | 4 ++-- 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 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) rename proto/{digitaltwin.proto => digital_twin/v1/digital_twin.proto} (97%) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index e5079d8d..23bfb566 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -7,8 +7,8 @@ extern crate iref; use log::Level::Debug; use log::{debug, info, log_enabled, warn}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use proto::digitaltwin::digital_twin_server::DigitalTwin; -use proto::digitaltwin::{ +use proto::digital_twin::digital_twin_server::DigitalTwin; +use proto::digital_twin::{ EntityAccessInfo, FindByIdRequest, FindByIdResponse, RegisterRequest, RegisterResponse, UnregisterRequest, UnregisterResponse, }; @@ -129,7 +129,7 @@ impl DigitalTwinImpl { mod digitaltwin_impl_tests { use super::*; use ibeji_common_test::set_dtdl_path; - use proto::digitaltwin::EndpointInfo; + use proto::digital_twin::EndpointInfo; #[tokio::test] async fn find_by_id_test() { diff --git a/in-vehicle-digital-twin/src/main.rs b/in-vehicle-digital-twin/src/main.rs index 2455836c..3b6a6be8 100644 --- a/in-vehicle-digital-twin/src/main.rs +++ b/in-vehicle-digital-twin/src/main.rs @@ -5,7 +5,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::RwLock; -use proto::digitaltwin::digital_twin_server::DigitalTwinServer; +use proto::digital_twin::digital_twin_server::DigitalTwinServer; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; diff --git a/proto/build.rs b/proto/build.rs index a4b07283..951f81f1 100644 --- a/proto/build.rs +++ b/proto/build.rs @@ -3,6 +3,6 @@ // SPDX-License-Identifier: MIT fn main() -> Result<(), Box> { - tonic_build::compile_protos("digitaltwin.proto")?; + tonic_build::compile_protos("digital_twin/v1/digital_twin.proto")?; Ok(()) } diff --git a/proto/digitaltwin.proto b/proto/digital_twin/v1/digital_twin.proto similarity index 97% rename from proto/digitaltwin.proto rename to proto/digital_twin/v1/digital_twin.proto index 0f44b318..493efc08 100644 --- a/proto/digitaltwin.proto +++ b/proto/digital_twin/v1/digital_twin.proto @@ -4,7 +4,7 @@ syntax = "proto3"; -package digitaltwin; +package digital_twin; service DigitalTwin { rpc FindById (FindByIdRequest) returns (FindByIdResponse); diff --git a/proto/src/lib.rs b/proto/src/lib.rs index f1d6300d..07e147e6 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -2,7 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -pub mod digitaltwin { +pub mod digital_twin { #![allow(clippy::derive_partial_eq_without_eq)] - tonic::include_proto!("digitaltwin"); + tonic::include_proto!("digital_twin"); } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 5e9ab35f..f1493b80 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -7,8 +7,8 @@ mod consumer_impl; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::FindByIdRequest; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::FindByIdRequest; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 2081a735..427f0b98 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -8,8 +8,8 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 77e67b42..ab337822 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -7,8 +7,8 @@ mod consumer_impl; use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::FindByIdRequest; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::FindByIdRequest; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::{ diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index f7e59dbf..80a002e0 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -9,8 +9,8 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 056e04d7..c77d00cb 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -5,8 +5,8 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::FindByIdRequest; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::FindByIdRequest; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 2e2e8785..476a43a9 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -8,8 +8,8 @@ use dt_model_identifiers::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; -use proto::digitaltwin::digital_twin_client::DigitalTwinClient; -use proto::digitaltwin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; From 28d926d72e067b265ab3d32dc88c94b467f12d1b Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Wed, 10 May 2023 11:15:11 -0700 Subject: [PATCH 17/41] Make protocol agnostic --- Cargo.toml | 2 +- common-test/src/lib.rs | 2 +- .../Cargo.toml | 2 +- .../dtdl/v2/content/sdv/vehicle.json | 0 .../src/lib.rs | 0 .../src/sdv_v1.rs | 0 dt-model/dt-model-identifiers/src/Cargo.toml | 12 ------------ samples/command/consumer/Cargo.toml | 2 +- samples/command/consumer/src/main.rs | 2 +- samples/command/provider/Cargo.toml | 2 +- samples/command/provider/src/main.rs | 2 +- samples/mixed/consumer/Cargo.toml | 2 +- samples/mixed/consumer/src/main.rs | 2 +- samples/mixed/provider/Cargo.toml | 2 +- samples/mixed/provider/src/main.rs | 2 +- samples/mixed/provider/src/provider_impl.rs | 2 +- samples/property/consumer/Cargo.toml | 2 +- samples/property/consumer/src/main.rs | 2 +- samples/property/provider/Cargo.toml | 2 +- samples/property/provider/src/main.rs | 2 +- 20 files changed, 16 insertions(+), 28 deletions(-) rename {dt-model/dt-model-identifiers => digital-twin-model}/Cargo.toml (88%) rename {dt-model => digital-twin-model}/dtdl/v2/content/sdv/vehicle.json (100%) rename {dt-model/dt-model-identifiers => digital-twin-model}/src/lib.rs (100%) rename {dt-model/dt-model-identifiers => digital-twin-model}/src/sdv_v1.rs (100%) delete mode 100644 dt-model/dt-model-identifiers/src/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 6250dd4b..169473aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ "common", "common-test", - "dt-model/dt-model-identifiers", + "digital-twin-model", "dtdl-parser", "in-vehicle-digital-twin", "samples/proto", diff --git a/common-test/src/lib.rs b/common-test/src/lib.rs index 496efcbd..2d6521b7 100644 --- a/common-test/src/lib.rs +++ b/common-test/src/lib.rs @@ -34,7 +34,7 @@ pub fn set_dtdl_path() { let repo_dir_result = get_repo_dir(); if let Some(repo_dir) = repo_dir_result { let value = format!( - "{repo_dir}/opendigitaltwins-dtdl/DTDL;{repo_dir}/iot-plugandplay-models;{repo_dir}/dtdl;{repo_dir}/dt-model/dtdl" + "{repo_dir}/opendigitaltwins-dtdl/DTDL;{repo_dir}/iot-plugandplay-models;{repo_dir}/dtdl;{repo_dir}/digital-twin-model/dtdl" ); env::set_var(DTDL_PATH, &value); trace!("{DTDL_PATH}={value}"); diff --git a/dt-model/dt-model-identifiers/Cargo.toml b/digital-twin-model/Cargo.toml similarity index 88% rename from dt-model/dt-model-identifiers/Cargo.toml rename to digital-twin-model/Cargo.toml index 1b13d2a1..f0bfe957 100644 --- a/dt-model/dt-model-identifiers/Cargo.toml +++ b/digital-twin-model/Cargo.toml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT [package] -name = "dt-model-identifiers" +name = "digital-twin-model" version = "0.1.0" edition = "2021" license = "MIT" diff --git a/dt-model/dtdl/v2/content/sdv/vehicle.json b/digital-twin-model/dtdl/v2/content/sdv/vehicle.json similarity index 100% rename from dt-model/dtdl/v2/content/sdv/vehicle.json rename to digital-twin-model/dtdl/v2/content/sdv/vehicle.json diff --git a/dt-model/dt-model-identifiers/src/lib.rs b/digital-twin-model/src/lib.rs similarity index 100% rename from dt-model/dt-model-identifiers/src/lib.rs rename to digital-twin-model/src/lib.rs diff --git a/dt-model/dt-model-identifiers/src/sdv_v1.rs b/digital-twin-model/src/sdv_v1.rs similarity index 100% rename from dt-model/dt-model-identifiers/src/sdv_v1.rs rename to digital-twin-model/src/sdv_v1.rs diff --git a/dt-model/dt-model-identifiers/src/Cargo.toml b/dt-model/dt-model-identifiers/src/Cargo.toml deleted file mode 100644 index e250d14a..00000000 --- a/dt-model/dt-model-identifiers/src/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT license. -# SPDX-License-Identifier: MIT - -[package] -name = "model-identifiers" -version = "0.1.0" -edition = "2021" -license = "MIT" - -[dependencies] - diff --git a/samples/command/consumer/Cargo.toml b/samples/command/consumer/Cargo.toml index 4176993f..71f1ea38 100644 --- a/samples/command/consumer/Cargo.toml +++ b/samples/command/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index f1493b80..7c6f3fd9 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -4,7 +4,7 @@ mod consumer_impl; -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; diff --git a/samples/command/provider/Cargo.toml b/samples/command/provider/Cargo.toml index 1801e2ac..7c4597d3 100644 --- a/samples/command/provider/Cargo.toml +++ b/samples/command/provider/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 427f0b98..2499290f 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -4,7 +4,7 @@ mod provider_impl; -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use parking_lot::Mutex; diff --git a/samples/mixed/consumer/Cargo.toml b/samples/mixed/consumer/Cargo.toml index 79a58793..5146ac8e 100644 --- a/samples/mixed/consumer/Cargo.toml +++ b/samples/mixed/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index ab337822..11087f01 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -4,7 +4,7 @@ mod consumer_impl; -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; diff --git a/samples/mixed/provider/Cargo.toml b/samples/mixed/provider/Cargo.toml index ae5b9b10..c7d5e3a6 100644 --- a/samples/mixed/provider/Cargo.toml +++ b/samples/mixed/provider/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index 80a002e0..cc1f033f 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -5,7 +5,7 @@ mod provider_impl; mod vehicle; -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; diff --git a/samples/mixed/provider/src/provider_impl.rs b/samples/mixed/provider/src/provider_impl.rs index cd134dd9..a7d2d60b 100644 --- a/samples/mixed/provider/src/provider_impl.rs +++ b/samples/mixed/provider/src/provider_impl.rs @@ -2,7 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use log::{debug, info, warn}; use parking_lot::{Mutex, MutexGuard}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; diff --git a/samples/property/consumer/Cargo.toml b/samples/property/consumer/Cargo.toml index 2c0d2f7c..179a4408 100644 --- a/samples/property/consumer/Cargo.toml +++ b/samples/property/consumer/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index c77d00cb..0aca496a 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -2,7 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; diff --git a/samples/property/provider/Cargo.toml b/samples/property/provider/Cargo.toml index 67b53e8c..12609dba 100644 --- a/samples/property/provider/Cargo.toml +++ b/samples/property/provider/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] async-std = { workspace = true, features = ["attributes"] } -dt-model-identifiers = { path = "../../../dt-model/dt-model-identifiers" } +digital-twin-model = { path = "../../../digital-twin-model" } env_logger= { workspace = true } ibeji-common = { path = "../../../common" } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 476a43a9..7a996917 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -4,7 +4,7 @@ mod provider_impl; -use dt_model_identifiers::sdv_v1 as sdv; +use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; From 9147330a9c22e8094e3a13dd0601966d9b685f31 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 13:53:02 -0700 Subject: [PATCH 18/41] Make protocol agnostic --- proto/Cargo.toml | 3 ++- proto/build.rs | 6 +++++- samples/property/provider/src/main.rs | 31 ++++++++++++++++++++++++++- samples/proto/src/lib.rs | 2 +- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/proto/Cargo.toml b/proto/Cargo.toml index a765f67a..418ea7a2 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -9,9 +9,10 @@ edition = "2021" license = "MIT" [dependencies] +prost = { workspace = true } +serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tonic = { workspace = true } -prost = { workspace = true } [build-dependencies] tonic-build = { workspace = true } diff --git a/proto/build.rs b/proto/build.rs index 951f81f1..09ad2859 100644 --- a/proto/build.rs +++ b/proto/build.rs @@ -3,6 +3,10 @@ // SPDX-License-Identifier: MIT fn main() -> Result<(), Box> { - tonic_build::compile_protos("digital_twin/v1/digital_twin.proto")?; + tonic_build::configure() + .message_attribute("EndpointInfo", "#[derive(serde::Deserialize, serde::Serialize)]") + .message_attribute("EntityAccessInfo", "#[derive(serde::Deserialize, serde::Serialize)]") + .compile(&["digital_twin/v1/digital_twin.proto"], &["digital_twin/v1/"])?; + Ok(()) } diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 7a996917..c4ac79ef 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -13,6 +13,7 @@ use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; +use serde_json::{json}; use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; @@ -100,6 +101,12 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); +/* + let expected = json!({ + "fingerprint": "0xF9BA143B95FF6D82", + "location": "Menlo Park, CA", + }); +*/ let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], @@ -114,6 +121,28 @@ async fn main() -> Result<(), Box> { endpoint_info_list: vec![endpoint_info], }; + let entity_access_info_list = vec!(entity_access_info); + + let v = serde_json::to_value(&entity_access_info_list).unwrap(); + println!("{}", v.to_string()); + + let j = json!( + [ + { + "description": "The immediate surroundings air temperature (in Fahrenheit).", + "endpoint_info_list": [ + { + "context": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + "operations":["Subscribe","Unsubscribe"], + "protocol":"grpc","uri":"http://[::1]:40010" + } + ], + "id": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + "name":"AmbientAirTemperature" + } + ]); + println!("{}", j.to_string()); + // Setup the HTTP server. let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); @@ -125,7 +154,7 @@ async fn main() -> Result<(), Box> { 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] }); + tonic::Request::new(RegisterRequest { entity_access_info_list }); let _response = client.register(request).await?; debug!("The Provider's DTDL has been registered."); diff --git a/samples/proto/src/lib.rs b/samples/proto/src/lib.rs index 5e12caa4..f624c0f9 100644 --- a/samples/proto/src/lib.rs +++ b/samples/proto/src/lib.rs @@ -2,7 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -#![allow(clippy::derive_partial_eq_without_eq)] +// #![allow(clippy::derive_partial_eq_without_eq)] pub mod sample_grpc { pub mod v1 { From 531fc313fb1350e04eccdde0963192402edcde90 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 14:01:43 -0700 Subject: [PATCH 19/41] Make protocol agnostic --- proto/build.rs | 2 +- samples/property/provider/src/main.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proto/build.rs b/proto/build.rs index 09ad2859..8f95dd99 100644 --- a/proto/build.rs +++ b/proto/build.rs @@ -5,7 +5,7 @@ fn main() -> Result<(), Box> { tonic_build::configure() .message_attribute("EndpointInfo", "#[derive(serde::Deserialize, serde::Serialize)]") - .message_attribute("EntityAccessInfo", "#[derive(serde::Deserialize, serde::Serialize)]") + .message_attribute("EntityAccessInfo", "#[derive(serde::Deserialize, serde::Serialize)]") .compile(&["digital_twin/v1/digital_twin.proto"], &["digital_twin/v1/"])?; Ok(()) diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index c4ac79ef..c6625ef8 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -124,7 +124,7 @@ async fn main() -> Result<(), Box> { let entity_access_info_list = vec!(entity_access_info); let v = serde_json::to_value(&entity_access_info_list).unwrap(); - println!("{}", v.to_string()); + println!("{}", v); let j = json!( [ @@ -135,13 +135,13 @@ async fn main() -> Result<(), Box> { "context": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), "operations":["Subscribe","Unsubscribe"], "protocol":"grpc","uri":"http://[::1]:40010" - } + } ], "id": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), "name":"AmbientAirTemperature" } ]); - println!("{}", j.to_string()); + println!("{}", j); // Setup the HTTP server. let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; From a9dacf313957b317cfb2a37872b585d91c20a71c Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 14:45:07 -0700 Subject: [PATCH 20/41] Make protocol agnostic --- samples/property/provider/src/main.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index c6625ef8..331fb555 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -13,7 +13,7 @@ use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; -use serde_json::{json}; +use serde_json::json; use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; @@ -101,12 +101,12 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); -/* - let expected = json!({ - "fingerprint": "0xF9BA143B95FF6D82", - "location": "Menlo Park, CA", - }); -*/ + /* + let expected = json!({ + "fingerprint": "0xF9BA143B95FF6D82", + "location": "Menlo Park, CA", + }); + */ let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], @@ -121,7 +121,7 @@ async fn main() -> Result<(), Box> { endpoint_info_list: vec![endpoint_info], }; - let entity_access_info_list = vec!(entity_access_info); + let entity_access_info_list = vec![entity_access_info]; let v = serde_json::to_value(&entity_access_info_list).unwrap(); println!("{}", v); @@ -153,8 +153,7 @@ async fn main() -> Result<(), Box> { 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 }); + let request = tonic::Request::new(RegisterRequest { entity_access_info_list }); let _response = client.register(request).await?; debug!("The Provider's DTDL has been registered."); From 9b150785dcb9f81c648733200a7b18f012098f31 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 16:50:33 -0700 Subject: [PATCH 21/41] Make protocol agnostic --- dtdl-parser/src/command_info_impl.rs | 24 +++++------ dtdl-parser/src/command_payload_info_impl.rs | 24 +++++------ dtdl-parser/src/component_info_impl.rs | 24 +++++------ dtdl-parser/src/dtmi.rs | 42 +++++++++---------- dtdl-parser/src/field_info_impl.rs | 23 +++++----- dtdl-parser/src/interface_info_impl.rs | 24 +++++------ dtdl-parser/src/model_parser.rs | 4 +- dtdl-parser/src/object_info_impl.rs | 23 +++++----- dtdl-parser/src/primitive_schema_info_impl.rs | 18 ++++---- dtdl-parser/src/property_info_impl.rs | 24 +++++------ dtdl-parser/src/relationship_info_impl.rs | 24 +++++------ dtdl-parser/src/telemetry_info_impl.rs | 24 +++++------ .../src/digitaltwin_impl.rs | 23 +++++----- samples/mixed/provider/src/provider_impl.rs | 4 +- samples/property/provider/src/main.rs | 31 +------------- .../property/provider/src/provider_impl.rs | 4 +- samples/proto/src/lib.rs | 2 - 17 files changed, 155 insertions(+), 187 deletions(-) diff --git a/dtdl-parser/src/command_info_impl.rs b/dtdl-parser/src/command_info_impl.rs index d1e9a985..5afc6093 100644 --- a/dtdl-parser/src/command_info_impl.rs +++ b/dtdl-parser/src/command_info_impl.rs @@ -225,21 +225,21 @@ mod command_info_impl_tests { command_info.add_undefined_property(String::from("first"), first_propery_value.clone()); command_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(command_info.dtdl_version() == 2); - assert!(command_info.id() == &id); + assert_eq!(command_info.dtdl_version(), 2); + assert_eq!(command_info.id(), &id); assert!(command_info.child_of().is_some()); - assert!(command_info.child_of().clone().unwrap() == child_of); + assert_eq!(command_info.child_of().clone().unwrap(), child_of); assert!(command_info.defined_in().is_some()); - assert!(command_info.defined_in().clone().unwrap() == defined_in); - assert!(command_info.entity_kind() == EntityKind::Command); - assert!(command_info.undefined_properties().len() == 2); - assert!( - command_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(command_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(command_info.entity_kind(), EntityKind::Command); + assert_eq!(command_info.undefined_properties().len(), 2); + assert_eq!( + command_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - command_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + command_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match command_info.name() { diff --git a/dtdl-parser/src/command_payload_info_impl.rs b/dtdl-parser/src/command_payload_info_impl.rs index d806ec82..bef167ec 100644 --- a/dtdl-parser/src/command_payload_info_impl.rs +++ b/dtdl-parser/src/command_payload_info_impl.rs @@ -183,27 +183,27 @@ mod command_payload_info_impl_tests { command_payload_info .add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(command_payload_info.dtdl_version() == DTDL_VERSION); - assert!(command_payload_info.id() == &id); + assert_eq!(command_payload_info.dtdl_version(), DTDL_VERSION); + assert_eq!(command_payload_info.id(), &id); assert!(command_payload_info.child_of().is_some()); - assert!(command_payload_info.child_of().clone().unwrap() == child_of); + assert_eq!(command_payload_info.child_of().clone().unwrap(), child_of); assert!(command_payload_info.defined_in().is_some()); - assert!(command_payload_info.defined_in().clone().unwrap() == defined_in); - assert!(command_payload_info.entity_kind() == EntityKind::CommandPayload); + assert_eq!(command_payload_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(command_payload_info.entity_kind(), EntityKind::CommandPayload); assert!(command_payload_info.schema().is_some()); match command_payload_info.schema() { Some(schema) => assert_eq!(schema.entity_kind(), EntityKind::String), None => return Err(String::from("schema has not been set")), } - assert!(command_payload_info.undefined_properties().len() == 2); - assert!( - command_payload_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(command_payload_info.undefined_properties().len(), 2); + assert_eq!( + command_payload_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - command_payload_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + command_payload_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match command_payload_info.name() { diff --git a/dtdl-parser/src/component_info_impl.rs b/dtdl-parser/src/component_info_impl.rs index 3e84b227..cb3fb200 100644 --- a/dtdl-parser/src/component_info_impl.rs +++ b/dtdl-parser/src/component_info_impl.rs @@ -176,21 +176,21 @@ mod component_info_impl_tests { component_info.add_undefined_property(String::from("first"), first_propery_value.clone()); component_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(component_info.dtdl_version() == 2); - assert!(component_info.id() == &id); + assert_eq!(component_info.dtdl_version(), 2); + assert_eq!(component_info.id(), &id); assert!(component_info.child_of().is_some()); - assert!(component_info.child_of().clone().unwrap() == child_of); + assert_eq!(component_info.child_of().clone().unwrap(), child_of); assert!(component_info.defined_in().is_some()); - assert!(component_info.defined_in().clone().unwrap() == defined_in); - assert!(component_info.entity_kind() == EntityKind::Component); - assert!(component_info.undefined_properties().len() == 2); - assert!( - component_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(component_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(component_info.entity_kind(), EntityKind::Component); + assert_eq!(component_info.undefined_properties().len(), 2); + assert_eq!( + component_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - component_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + component_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match component_info.name() { diff --git a/dtdl-parser/src/dtmi.rs b/dtdl-parser/src/dtmi.rs index c616cf8c..9bc6f23d 100644 --- a/dtdl-parser/src/dtmi.rs +++ b/dtdl-parser/src/dtmi.rs @@ -176,24 +176,24 @@ mod dmti_tests { assert!(new_dtmi_result.is_ok()); let mut dtmi: Dtmi = new_dtmi_result.unwrap(); assert!(dtmi.major_version().is_some()); - assert!(dtmi.major_version().unwrap() == 1); + assert_eq!(dtmi.major_version().unwrap(), 1); assert!(dtmi.minor_version().is_some()); - assert!(dtmi.minor_version().unwrap() == 234); - assert!(dtmi.complete_version() == 1.000234); - assert!(dtmi.versionless() == "dtmi:com:example:Thermostat"); - assert!(dtmi.labels().len() == 3); - assert!(dtmi.labels()[0] == "com"); - assert!(dtmi.labels()[1] == "example"); - assert!(dtmi.labels()[2] == "Thermostat"); - assert!(dtmi.absolute_path == "com:example:Thermostat"); - assert!(dtmi.fragment() == "some-fragment"); - assert!(format!("{dtmi}") == "dtmi:com:example:Thermostat;1.234#some-fragment"); + assert_eq!(dtmi.minor_version().unwrap(), 234); + assert_eq!(dtmi.complete_version(), 1.000234); + assert_eq!(dtmi.versionless(), "dtmi:com:example:Thermostat"); + assert_eq!(dtmi.labels().len(), 3); + assert_eq!(dtmi.labels()[0], "com"); + assert_eq!(dtmi.labels()[1], "example"); + assert_eq!(dtmi.labels()[2], "Thermostat"); + assert_eq!(dtmi.absolute_path, "com:example:Thermostat"); + assert_eq!(dtmi.fragment(), "some-fragment"); + assert_eq!(format!("{dtmi}"), "dtmi:com:example:Thermostat;1.234#some-fragment"); new_dtmi_result = Dtmi::new("dtmi:com:example:Thermostat;1.234#"); assert!(new_dtmi_result.is_ok()); dtmi = new_dtmi_result.unwrap(); - assert!(dtmi.fragment() == ""); - assert!(format!("{dtmi}") == "dtmi:com:example:Thermostat;1.234#"); + assert_eq!(dtmi.fragment(), ""); + assert_eq!(format!("{dtmi}"), "dtmi:com:example:Thermostat;1.234#"); } #[test] @@ -205,13 +205,13 @@ mod dmti_tests { assert!(dtmi.major_version().unwrap() == 1); assert!(dtmi.minor_version().is_some()); assert!(dtmi.minor_version().unwrap() == 234567); - assert!(dtmi.complete_version() == 1.234567); - assert!(dtmi.versionless() == "dtmi:com:example:Thermostat"); - assert!(dtmi.labels().len() == 3); - assert!(dtmi.labels()[0] == "com"); - assert!(dtmi.labels()[1] == "example"); - assert!(dtmi.labels()[2] == "Thermostat"); - assert!(dtmi.absolute_path == "com:example:Thermostat"); + assert_eq!(dtmi.complete_version(), 1.234567); + assert_eq!(dtmi.versionless(), "dtmi:com:example:Thermostat"); + assert_eq!(dtmi.labels().len(), 3); + assert_eq!(dtmi.labels()[0], "com"); + assert_eq!(dtmi.labels()[1], "example"); + assert_eq!(dtmi.labels()[2], "Thermostat"); + assert_eq!(dtmi.absolute_path, "com:example:Thermostat"); } #[test] @@ -244,7 +244,7 @@ mod dmti_tests { assert!(third_create_dtmi_result.is_some()); let third_dtmi = third_create_dtmi_result.unwrap(); - assert!(first_dtmi == second_dtmi); + assert_eq!(first_dtmi, second_dtmi); assert!(first_dtmi != third_dtmi); } } diff --git a/dtdl-parser/src/field_info_impl.rs b/dtdl-parser/src/field_info_impl.rs index a5303606..c9b4bb75 100644 --- a/dtdl-parser/src/field_info_impl.rs +++ b/dtdl-parser/src/field_info_impl.rs @@ -189,20 +189,21 @@ mod field_info_impl_tests { field_info.add_undefined_property(String::from("first"), first_propery_value.clone()); field_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(field_info.dtdl_version() == 2); - assert!(field_info.id() == &id); + assert_eq!(field_info.dtdl_version(), 2); + assert_eq!(field_info.id(), &id); assert!(field_info.child_of().is_some()); - assert!(field_info.child_of().clone().unwrap() == child_of); + assert_eq!(field_info.child_of().clone().unwrap(), child_of); assert!(field_info.defined_in().is_some()); - assert!(field_info.defined_in().clone().unwrap() == defined_in); - assert!(field_info.entity_kind() == EntityKind::Telemetry); - assert!(field_info.undefined_properties().len() == 2); - assert!( - field_info.undefined_properties().get("first").unwrap().clone() == first_propery_value + assert_eq!(field_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(field_info.entity_kind(), EntityKind::Telemetry); + assert_eq!(field_info.undefined_properties().len(), 2); + assert_eq!( + field_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - field_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + field_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match field_info.name() { diff --git a/dtdl-parser/src/interface_info_impl.rs b/dtdl-parser/src/interface_info_impl.rs index 9acdaf81..ec64adca 100644 --- a/dtdl-parser/src/interface_info_impl.rs +++ b/dtdl-parser/src/interface_info_impl.rs @@ -139,21 +139,21 @@ mod interface_info_impl_tests { interface_info.add_undefined_property(String::from("first"), first_propery_value.clone()); interface_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(interface_info.dtdl_version() == 2); - assert!(interface_info.id() == &id); + assert_eq!(interface_info.dtdl_version(), 2); + assert_eq!(interface_info.id(), &id); assert!(interface_info.child_of().is_some()); - assert!(interface_info.child_of().clone().unwrap() == child_of); + assert_eq!(interface_info.child_of().clone().unwrap(), child_of); assert!(interface_info.defined_in().is_some()); - assert!(interface_info.defined_in().clone().unwrap() == defined_in); - assert!(interface_info.entity_kind() == EntityKind::Interface); - assert!(interface_info.undefined_properties().len() == 2); - assert!( - interface_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(interface_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(interface_info.entity_kind(), EntityKind::Interface); + assert_eq!(interface_info.undefined_properties().len(), 2); + assert_eq!( + interface_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - interface_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + interface_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); } } diff --git a/dtdl-parser/src/model_parser.rs b/dtdl-parser/src/model_parser.rs index e92f76fb..fc464e2a 100644 --- a/dtdl-parser/src/model_parser.rs +++ b/dtdl-parser/src/model_parser.rs @@ -1086,8 +1086,8 @@ mod model_parser_tests { model_dict_result.err().unwrap() ); let model_dict = model_dict_result.unwrap(); - assert!( - model_dict.len() == 31, + assert_eq!( + model_dict.len(), 31, "expected length was 31, actual length is {}", model_dict.len() ); diff --git a/dtdl-parser/src/object_info_impl.rs b/dtdl-parser/src/object_info_impl.rs index f84ee1e1..f2fa6ec5 100644 --- a/dtdl-parser/src/object_info_impl.rs +++ b/dtdl-parser/src/object_info_impl.rs @@ -159,20 +159,21 @@ mod object_info_impl_tests { object_info.add_undefined_property(String::from("first"), first_propery_value.clone()); object_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(object_info.dtdl_version() == 2); - assert!(object_info.id() == &id); + assert_eq!(object_info.dtdl_version(), 2); + assert_eq!(object_info.id(), &id); assert!(object_info.child_of().is_some()); - assert!(object_info.child_of().clone().unwrap() == child_of); + assert_eq!(object_info.child_of().clone().unwrap(), child_of); assert!(object_info.defined_in().is_some()); - assert!(object_info.defined_in().clone().unwrap() == defined_in); - assert!(object_info.entity_kind() == EntityKind::Object); - assert!(object_info.undefined_properties().len() == 2); - assert!( - object_info.undefined_properties().get("first").unwrap().clone() == first_propery_value + assert_eq!(object_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(object_info.entity_kind(), EntityKind::Object); + assert_eq!(object_info.undefined_properties().len(), 2); + assert_eq!( + object_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - object_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + object_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match object_info.fields() { diff --git a/dtdl-parser/src/primitive_schema_info_impl.rs b/dtdl-parser/src/primitive_schema_info_impl.rs index 3e3b4ca7..6fae4032 100644 --- a/dtdl-parser/src/primitive_schema_info_impl.rs +++ b/dtdl-parser/src/primitive_schema_info_impl.rs @@ -136,19 +136,19 @@ mod primitive_schema_info_impl_tests { primitive_schema_info .add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(primitive_schema_info.dtdl_version() == 2); - assert!(primitive_schema_info.id() == &id); + assert_eq!(primitive_schema_info.dtdl_version(), 2); + assert_eq!(primitive_schema_info.id(), &id); assert!(primitive_schema_info.child_of().is_none()); assert!(primitive_schema_info.defined_in().is_none()); assert!(primitive_schema_info.entity_kind() == EntityKind::String); - assert!(primitive_schema_info.undefined_properties().len() == 2); - assert!( - primitive_schema_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(primitive_schema_info.undefined_properties().len(), 2); + assert_eq!( + primitive_schema_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - primitive_schema_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + primitive_schema_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); } } diff --git a/dtdl-parser/src/property_info_impl.rs b/dtdl-parser/src/property_info_impl.rs index 6e5f3800..26140866 100644 --- a/dtdl-parser/src/property_info_impl.rs +++ b/dtdl-parser/src/property_info_impl.rs @@ -190,21 +190,21 @@ mod property_info_impl_tests { property_info.add_undefined_property(String::from("first"), first_propery_value.clone()); property_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(property_info.dtdl_version() == 2); - assert!(property_info.id() == &id); + assert_eq!(property_info.dtdl_version(), 2); + assert_eq!(property_info.id(), &id); assert!(property_info.child_of().is_some()); - assert!(property_info.child_of().clone().unwrap() == child_of); + assert_eq!(property_info.child_of().clone().unwrap(), child_of); assert!(property_info.defined_in().is_some()); - assert!(property_info.defined_in().clone().unwrap() == defined_in); - assert!(property_info.entity_kind() == EntityKind::Property); - assert!(property_info.undefined_properties().len() == 2); - assert!( - property_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(property_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(property_info.entity_kind(), EntityKind::Property); + assert_eq!(property_info.undefined_properties().len(), 2); + assert_eq!( + property_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - property_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + property_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match property_info.name() { diff --git a/dtdl-parser/src/relationship_info_impl.rs b/dtdl-parser/src/relationship_info_impl.rs index 838ff36c..caf4f4bc 100644 --- a/dtdl-parser/src/relationship_info_impl.rs +++ b/dtdl-parser/src/relationship_info_impl.rs @@ -193,21 +193,21 @@ mod relationship_info_impl_tests { relationship_info .add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(relationship_info.dtdl_version() == 2); - assert!(relationship_info.id() == &id); + assert_eq!(relationship_info.dtdl_version(), 2); + assert_eq!(relationship_info.id(), &id); assert!(relationship_info.child_of().is_some()); - assert!(relationship_info.child_of().clone().unwrap() == child_of); + assert_eq!(relationship_info.child_of().clone().unwrap(), child_of); assert!(relationship_info.defined_in().is_some()); - assert!(relationship_info.defined_in().clone().unwrap() == defined_in); - assert!(relationship_info.entity_kind() == EntityKind::Property); - assert!(relationship_info.undefined_properties().len() == 2); - assert!( - relationship_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(relationship_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(relationship_info.entity_kind(), EntityKind::Property); + assert_eq!(relationship_info.undefined_properties().len(), 2); + assert_eq!( + relationship_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - relationship_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + relationship_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match relationship_info.name() { diff --git a/dtdl-parser/src/telemetry_info_impl.rs b/dtdl-parser/src/telemetry_info_impl.rs index b329f8f4..5f4c7f49 100644 --- a/dtdl-parser/src/telemetry_info_impl.rs +++ b/dtdl-parser/src/telemetry_info_impl.rs @@ -181,21 +181,21 @@ mod telemetry_info_impl_tests { telemetry_info.add_undefined_property(String::from("first"), first_propery_value.clone()); telemetry_info.add_undefined_property(String::from("second"), second_propery_value.clone()); - assert!(telemetry_info.dtdl_version() == 2); - assert!(telemetry_info.id() == &id); + assert_eq!(telemetry_info.dtdl_version(), 2); + assert_eq!(telemetry_info.id(), &id); assert!(telemetry_info.child_of().is_some()); - assert!(telemetry_info.child_of().clone().unwrap() == child_of); + assert_eq!(telemetry_info.child_of().clone().unwrap(), child_of); assert!(telemetry_info.defined_in().is_some()); - assert!(telemetry_info.defined_in().clone().unwrap() == defined_in); - assert!(telemetry_info.entity_kind() == EntityKind::Telemetry); - assert!(telemetry_info.undefined_properties().len() == 2); - assert!( - telemetry_info.undefined_properties().get("first").unwrap().clone() - == first_propery_value + assert_eq!(telemetry_info.defined_in().clone().unwrap(), defined_in); + assert_eq!(telemetry_info.entity_kind(), EntityKind::Telemetry); + assert_eq!(telemetry_info.undefined_properties().len(), 2); + assert_eq!( + telemetry_info.undefined_properties().get("first").unwrap().clone(), + first_propery_value ); - assert!( - telemetry_info.undefined_properties().get("second").unwrap().clone() - == second_propery_value + assert_eq!( + telemetry_info.undefined_properties().get("second").unwrap().clone(), + second_propery_value ); match telemetry_info.name() { diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 23bfb566..08f6183d 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -31,9 +31,7 @@ impl DigitalTwin for DigitalTwinImpl { &self, request: Request, ) -> Result, Status> { - let request_inner = request.into_inner(); - - let entity_id = request_inner.id; + let entity_id = request.into_inner().id; info!("Received a find_by_id request for entity id {entity_id}"); @@ -48,6 +46,10 @@ impl DigitalTwin for DigitalTwinImpl { info!("{entity_access_info:?}"); + if entity_access_info.is_none() { + return Err(Status::not_found("Unable to find the entity with id {entity_id}")); + } + let response = FindByIdResponse { entity_access_info }; debug!("Responded to the find_by_id request."); @@ -68,12 +70,7 @@ impl DigitalTwin for DigitalTwinImpl { for entity_access_info in &request_inner.entity_access_info_list { info!("Received a register request for the the entity:\n{}", entity_access_info.id); - match self.register_entity(entity_access_info.clone()) { - Ok(_) => { - self.register_entity(entity_access_info.clone()).map_err(Status::internal)? - } - Err(error) => return Err(Status::internal(error)), - }; + self.register_entity(entity_access_info.clone()).map_err(Status::internal)?; } let response = RegisterResponse {}; @@ -173,9 +170,9 @@ mod digitaltwin_impl_tests { assert!(response_inner.entity_access_info.is_some()); - assert!( - response_inner.entity_access_info.unwrap().id - == "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" + assert_eq!( + response_inner.entity_access_info.unwrap().id, + "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" ); // TODO: add check @@ -222,7 +219,7 @@ mod digitaltwin_impl_tests { let lock: RwLockReadGuard> = entity_access_info_map.read(); // Make sure that we populated the entity map from the contents of the DTDL. - assert!(lock.len() == 1, "expected length was 1, actual length is {}", lock.len()); + assert_eq!(lock.len(), 1, "expected length was 1, actual length is {}", lock.len()); } } } diff --git a/samples/mixed/provider/src/provider_impl.rs b/samples/mixed/provider/src/provider_impl.rs index a7d2d60b..79e9d830 100644 --- a/samples/mixed/provider/src/provider_impl.rs +++ b/samples/mixed/provider/src/provider_impl.rs @@ -240,14 +240,14 @@ mod provider_impl_tests { let first_get_result = lock.get(&first_id); assert!(first_get_result.is_some()); let first_value = first_get_result.unwrap(); - assert!(first_value.len() == 2); + assert_eq!(first_value.len(), 2); assert!(first_value.contains(&first_uri)); assert!(first_value.contains(&second_uri)); let second_get_result = lock.get(&second_id); assert!(second_get_result.is_some()); let second_value = second_get_result.unwrap(); - assert!(second_value.len() == 1); + assert_eq!(second_value.len(), 1); assert!(second_value.contains(&third_uri)); } } diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 331fb555..8e0e21c9 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -13,7 +13,6 @@ use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; -use serde_json::json; use std::collections::HashSet; use std::net::SocketAddr; use std::sync::Arc; @@ -101,12 +100,6 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); - /* - let expected = json!({ - "fingerprint": "0xF9BA143B95FF6D82", - "location": "Menlo Park, CA", - }); - */ let endpoint_info = EndpointInfo { protocol: String::from("grpc"), operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], @@ -121,28 +114,6 @@ async fn main() -> Result<(), Box> { endpoint_info_list: vec![endpoint_info], }; - let entity_access_info_list = vec![entity_access_info]; - - let v = serde_json::to_value(&entity_access_info_list).unwrap(); - println!("{}", v); - - let j = json!( - [ - { - "description": "The immediate surroundings air temperature (in Fahrenheit).", - "endpoint_info_list": [ - { - "context": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), - "operations":["Subscribe","Unsubscribe"], - "protocol":"grpc","uri":"http://[::1]:40010" - } - ], - "id": String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), - "name":"AmbientAirTemperature" - } - ]); - println!("{}", j); - // Setup the HTTP server. let addr: SocketAddr = PROVIDER_AUTHORITY.parse()?; let subscription_map = Arc::new(Mutex::new(SubscriptionMap::new())); @@ -153,7 +124,7 @@ async fn main() -> Result<(), Box> { 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 }); + 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."); diff --git a/samples/property/provider/src/provider_impl.rs b/samples/property/provider/src/provider_impl.rs index 6bc8e1eb..7c889a9e 100644 --- a/samples/property/provider/src/provider_impl.rs +++ b/samples/property/provider/src/provider_impl.rs @@ -146,14 +146,14 @@ mod provider_impl_tests { let first_get_result = lock.get(&first_id); assert!(first_get_result.is_some()); let first_value = first_get_result.unwrap(); - assert!(first_value.len() == 2); + assert_eq!(first_value.len(), 2); assert!(first_value.contains(&first_uri)); assert!(first_value.contains(&second_uri)); let second_get_result = lock.get(&second_id); assert!(second_get_result.is_some()); let second_value = second_get_result.unwrap(); - assert!(second_value.len() == 1); + assert_eq!(second_value.len(), 1); assert!(second_value.contains(&third_uri)); } } diff --git a/samples/proto/src/lib.rs b/samples/proto/src/lib.rs index f624c0f9..2e86a309 100644 --- a/samples/proto/src/lib.rs +++ b/samples/proto/src/lib.rs @@ -2,8 +2,6 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT -// #![allow(clippy::derive_partial_eq_without_eq)] - pub mod sample_grpc { pub mod v1 { pub mod digital_twin_consumer { From 5787bc09187893cc909dc16cee4ee323a8ff0bc4 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 16:54:11 -0700 Subject: [PATCH 22/41] Make protocol agnostic --- dtdl-parser/src/model_parser.rs | 3 ++- samples/property/provider/src/main.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dtdl-parser/src/model_parser.rs b/dtdl-parser/src/model_parser.rs index fc464e2a..d0541a48 100644 --- a/dtdl-parser/src/model_parser.rs +++ b/dtdl-parser/src/model_parser.rs @@ -1087,7 +1087,8 @@ mod model_parser_tests { ); let model_dict = model_dict_result.unwrap(); assert_eq!( - model_dict.len(), 31, + model_dict.len(), + 31, "expected length was 31, actual length is {}", model_dict.len() ); diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 8e0e21c9..7a996917 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -124,7 +124,8 @@ async fn main() -> Result<(), Box> { 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 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."); From c91519f9cc4b8eae4f8876e4f47ebea4bee20e16 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Thu, 11 May 2023 17:04:44 -0700 Subject: [PATCH 23/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 08f6183d..047da773 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -114,9 +114,7 @@ impl DigitalTwinImpl { }; } - if log_enabled!(Debug) { - debug!("Registered entity {}", &entity_access_info.id); - } + debug!("Registered entity {}", &entity_access_info.id); Ok(()) } From d879f549e18d6fd71a7cac09bb01bb492a6c3097 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 14:03:00 -0700 Subject: [PATCH 24/41] Make protocol agnostic --- Cargo.toml | 1 + README.md | 9 -- .../src/digitaltwin_impl.rs | 26 +++--- samples/command/consumer/Cargo.toml | 1 + samples/command/consumer/src/main.rs | 1 + samples/command/provider/Cargo.toml | 1 + samples/common/Cargo.toml | 9 ++ samples/common/src/lib.rs | 57 ++++++++++++ samples/mixed/consumer/Cargo.toml | 1 + samples/mixed/consumer/src/main.rs | 87 +++++++++++++------ samples/mixed/provider/Cargo.toml | 1 + samples/mixed/provider/src/main.rs | 73 +++++++++------- samples/property/consumer/Cargo.toml | 1 + samples/property/consumer/src/main.rs | 3 +- samples/property/provider/Cargo.toml | 1 + 15 files changed, 186 insertions(+), 86 deletions(-) create mode 100644 samples/common/Cargo.toml create mode 100644 samples/common/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 169473aa..7b108376 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "digital-twin-model", "dtdl-parser", "in-vehicle-digital-twin", + "samples/common", "samples/proto", "samples/command/consumer", "samples/command/provider", diff --git a/README.md b/README.md index ede08cf7..1f10c664 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,6 @@ 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 run the following command to set the DTDL_PATH environment variable. -Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

-`export DTDL_PATH="{repo-root-dir}/opendigitaltwins-dtdl/DTDL;{repo-root-dir}/dtdl;{repo-root-dir}/samples/property/dtdl"`
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`
@@ -133,9 +130,6 @@ 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 run the following command to set the DTDL_PATH environment variable. -Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

-`export DTDL_PATH="{repo-root-dir}/opendigitaltwins-dtdl/DTDL;{repo-root-dir}/dtdl;{repo-root-dir}/samples/command/dtdl"`
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`
@@ -162,9 +156,6 @@ 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 run the following command to set the DTDL_PATH environment variable. -Make sure that you replace "{repo-root-dir}" with the repository root directory on the machine where you are running the demo.

-`export DTDL_PATH="{repo-root-dir}/opendigitaltwins-dtdl/DTDL;{repo-root-dir}/dtdl;{repo-root-dir}/samples/mixed/dtdl"`
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`
diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 047da773..60266e94 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -4,8 +4,7 @@ extern crate iref; -use log::Level::Debug; -use log::{debug, info, log_enabled, warn}; +use log::{debug, info, warn}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use proto::digital_twin::digital_twin_server::DigitalTwin; use proto::digital_twin::{ @@ -70,7 +69,7 @@ impl DigitalTwin for DigitalTwinImpl { for entity_access_info in &request_inner.entity_access_info_list { info!("Received a register request for the the entity:\n{}", entity_access_info.id); - self.register_entity(entity_access_info.clone()).map_err(Status::internal)?; + self.register_entity(entity_access_info.clone())?; } let response = RegisterResponse {}; @@ -99,14 +98,14 @@ impl DigitalTwinImpl { /// /// # Arguments /// * `entity` - The entity. - fn register_entity(&self, entity_access_info: EntityAccessInfo) -> Result<(), String> { + 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) { Some(_) => { - // TODO: merge existing contents with new contents + return Err(Status::unimplemented("The in-vehicle digital twin service does not yet support multiple registrations of the same entity.")); } None => { lock.insert(entity_access_info.id.clone(), entity_access_info.clone()); @@ -168,12 +167,14 @@ mod digitaltwin_impl_tests { assert!(response_inner.entity_access_info.is_some()); + let response_entity_access_info = response_inner.entity_access_info.unwrap(); + assert_eq!( - response_inner.entity_access_info.unwrap().id, + response_entity_access_info.id, "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1" ); - - // TODO: add check + 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"); } #[tokio::test] @@ -199,18 +200,11 @@ mod digitaltwin_impl_tests { 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(RegisterRequest { entity_access_info_list: vec![entity_access_info], }); let result = digital_twin_impl.register(request).await; - assert!(result.is_ok()); + assert!(result.is_ok(), "register result is not okay: {result:?}"); // This block controls the lifetime of the lock. { diff --git a/samples/command/consumer/Cargo.toml b/samples/command/consumer/Cargo.toml index 71f1ea38..7ae856cc 100644 --- a/samples/command/consumer/Cargo.toml +++ b/samples/command/consumer/Cargo.toml @@ -17,6 +17,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 7c6f3fd9..99f2f485 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -9,6 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::FindByIdRequest; +use samples_common::digital_twin_operation; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; diff --git a/samples/command/provider/Cargo.toml b/samples/command/provider/Cargo.toml index 7c4597d3..61eb2773 100644 --- a/samples/command/provider/Cargo.toml +++ b/samples/command/provider/Cargo.toml @@ -18,6 +18,7 @@ log = { workspace = true} parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/samples/common/Cargo.toml b/samples/common/Cargo.toml new file mode 100644 index 00000000..01c4760f --- /dev/null +++ b/samples/common/Cargo.toml @@ -0,0 +1,9 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +[package] +name = "samples_common" +version = "0.1.0" +edition = "2021" +license = "MIT" diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs new file mode 100644 index 00000000..561dcebf --- /dev/null +++ b/samples/common/src/lib.rs @@ -0,0 +1,57 @@ +// 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"; +} + +/// Is the provided subset a subset of the provided superset? +/// +/// # Arguments +/// `subset` - The provided subset. +/// `superset` - The provided superset. +pub fn is_subset(subset: &Vec, superset: &Vec) -> bool { + subset.iter().all(|subset_member| { + superset.iter().any(|supserset_member| subset_member == supserset_member) + }) +} + +#[cfg(test)] +mod ibeji_common_tests { + use super::*; + + #[test] + fn is_subset_test() { + assert!(is_subset(&vec!(), &vec!())); + assert!(is_subset(&vec!(), &vec!("one".to_string()))); + assert!(is_subset(&vec!(), &vec!("one".to_string(), "two".to_string()))); + assert!(is_subset(&vec!("one".to_string()), &vec!("one".to_string(), "two".to_string()))); + assert!(is_subset( + &vec!("one".to_string(), "two".to_string()), + &vec!("one".to_string(), "two".to_string()) + )); + assert!(!is_subset( + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!("one".to_string(), "two".to_string()) + )); + assert!(!is_subset( + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!("one".to_string()) + )); + assert!(!is_subset( + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!() + )); + } +} diff --git a/samples/mixed/consumer/Cargo.toml b/samples/mixed/consumer/Cargo.toml index 5146ac8e..414430f0 100644 --- a/samples/mixed/consumer/Cargo.toml +++ b/samples/mixed/consumer/Cargo.toml @@ -17,6 +17,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 11087f01..59182e58 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -9,6 +9,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::FindByIdRequest; +use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::{ @@ -32,7 +33,7 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) debug!("Starting the Consumer's show-notification repeater."); tokio::spawn(async move { loop { - let payload: String = String::from("show-notification request"); + let payload: String = "show-notification request".to_string(); info!("Sending an invoke request on entity {} with payload '{payload} to provider URI {provider_uri}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); @@ -48,9 +49,8 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) let response_id = Uuid::new_v4().to_string(); let request = tonic::Request::new(InvokeRequest { - entity_id: String::from( - sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, - ), + entity_id: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID + .to_string(), consumer_uri: consumer_uri.clone(), response_id, payload, @@ -92,7 +92,7 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { let value: String = format!("{is_active}"); let request = tonic::Request::new(SetRequest { - entity_id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), + entity_id: sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID.to_string(), value, }); @@ -109,27 +109,39 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { }); } -async fn get_provider_uri(entity_id: &str) -> Result { - // Obtain the DTDL for the send_notification command. +async fn get_provider_uri( + entity_id: &str, + protocol: &str, + operations: &Vec, +) -> Result { info!("Sending a find_by_id request for entity id {entity_id} 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 .map_err(|error| format!("{error}"))?; - let request = tonic::Request::new(FindByIdRequest { id: String::from(entity_id) }); + 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 provider_uri = match response_inner.entity_access_info { - Some(content) => { - // TODO: select the right one, rather than just using the first one - content.endpoint_info_list[0].uri.clone() - } - None => { - panic!("Did not find an entity for the AmbientAirTemperature command"); + let entity_access_info = response_inner + .entity_access_info + .expect("Did not find an entity for the AmbientAirTemperature property"); + + let mut provider_uri_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) { + provider_uri_option = Some(endpoint_info.uri); + break; } - }; + } + + if provider_uri_option.is_none() { + return Err("Did not find an endpoint that met our requirements".to_string()); + } + + let provider_uri = provider_uri_option.unwrap(); info!("The provider URI for entity id {entity_id} is {provider_uri}"); @@ -144,7 +156,7 @@ async fn send_subscribe_request( 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 request = tonic::Request::new(SubscribeRequest { - entity_id: String::from(entity_id), + entity_id: entity_id.to_string(), consumer_uri: consumer_uri.to_string(), }); let _response = client.subscribe(request).await?; @@ -166,19 +178,40 @@ 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_uri = - get_provider_uri(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID) - .await - .unwrap(); + let show_notification_command_provider_uri = get_provider_uri( + sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, + digital_twin_protocol::GRPC, + &vec![digital_twin_operation::INVOKE.to_string()], + ) + .await + .unwrap(); - let ambient_air_temperature_property_provider_uri = - get_provider_uri(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID).await.unwrap(); + let ambient_air_temperature_property_provider_uri = get_provider_uri( + sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, + digital_twin_protocol::GRPC, + &vec![digital_twin_operation::SUBSCRIBE.to_string()], + ) + .await + .unwrap(); - let is_air_conditioning_active_property_uri = - get_provider_uri(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID).await.unwrap(); + let is_air_conditioning_active_property_uri = get_provider_uri( + sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, + digital_twin_protocol::GRPC, + &vec![ + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::SET.to_string(), + ], + ) + .await + .unwrap(); - let hybrid_battery_remaining_property_uri = - get_provider_uri(sdv::vehicle::obd::hybrid_battery_remaining::ID).await.unwrap(); + let hybrid_battery_remaining_property_uri = get_provider_uri( + sdv::vehicle::obd::hybrid_battery_remaining::ID, + digital_twin_protocol::GRPC, + &vec![digital_twin_operation::SUBSCRIBE.to_string()], + ) + .await + .unwrap(); let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 diff --git a/samples/mixed/provider/Cargo.toml b/samples/mixed/provider/Cargo.toml index c7d5e3a6..7a65409e 100644 --- a/samples/mixed/provider/Cargo.toml +++ b/samples/mixed/provider/Cargo.toml @@ -18,6 +18,7 @@ log = { workspace = true } parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true , features = ["macros", "rt-multi-thread"] } diff --git a/samples/mixed/provider/src/main.rs b/samples/mixed/provider/src/main.rs index cc1f033f..8d473195 100644 --- a/samples/mixed/provider/src/main.rs +++ b/samples/mixed/provider/src/main.rs @@ -11,6 +11,7 @@ use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use samples_common::{digital_twin_operation, digital_twin_protocol}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; @@ -53,8 +54,8 @@ async fn publish(subscription_map: Arc>, entity_id: &str, let mut client = client_result.unwrap(); let request = tonic::Request::new(PublishRequest { - entity_id: String::from(entity_id), - value: String::from(value), + entity_id: entity_id.to_string(), + value: value.to_string(), }); let response = client.publish(request).await; @@ -116,7 +117,7 @@ async fn start_vehicle_simulator( } #[tokio::main] -#[allow(clippy::collapsible_else_if)] +// #[allow(clippy::collapsible_else_if)] async fn main() -> Result<(), Box> { // Setup logging. Builder::new().filter(None, LevelFilter::Info).target(Target::Stdout).init(); @@ -125,61 +126,67 @@ async fn main() -> Result<(), Box> { // AmbientAirTemperature let ambient_air_temperature_endpoint_info = EndpointInfo { - protocol: String::from("grpc"), - operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + 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: String::from("AmbientAirTemperature"), - id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), - description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), + 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: String::from("grpc"), + protocol: digital_twin_protocol::GRPC.to_string(), operations: vec![ - String::from("Subscribe"), - String::from("Unsubscribe"), - String::from("Get"), + digital_twin_operation::SUBSCRIBE.to_string(), + digital_twin_operation::UNSUBSCRIBE.to_string(), + digital_twin_operation::SET.to_string(), ], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + 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: String::from("IsAirConditioningActive"), - id: String::from(sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID), - description: String::from("Is air conditioning active?"), + 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: String::from("grpc"), - operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), + 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: String::from("HybridBatteryRemaining"), - id: String::from(sdv::vehicle::obd::hybrid_battery_remaining::ID), - description: String::from("The remaining hybrid battery life."), + 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: String::from("grpc"), - operations: vec![String::from("Invoke")], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + 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: String::from("ShowNotification"), - id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), - description: String::from("Show a notification on the HMI."), + 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], }; diff --git a/samples/property/consumer/Cargo.toml b/samples/property/consumer/Cargo.toml index 179a4408..6faf3e54 100644 --- a/samples/property/consumer/Cargo.toml +++ b/samples/property/consumer/Cargo.toml @@ -17,6 +17,7 @@ json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "reso log = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index 0aca496a..cc8c9db0 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -7,6 +7,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::FindByIdRequest; +use samples_common::digital_twin_operation; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; @@ -64,7 +65,7 @@ async fn main() -> Result<(), Box> { ); let mut client = DigitalTwinProviderClient::connect(provider_uri).await?; let request = tonic::Request::new(SubscribeRequest { - entity_id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + entity_id: sdv::vehicle::cabin::hvac::ambient_air_temperature::ID.to_string(), consumer_uri, }); let _response = client.subscribe(request).await?; diff --git a/samples/property/provider/Cargo.toml b/samples/property/provider/Cargo.toml index 12609dba..77568949 100644 --- a/samples/property/provider/Cargo.toml +++ b/samples/property/provider/Cargo.toml @@ -18,6 +18,7 @@ log = { workspace = true} parking_lot = { workspace = true } prost = { workspace = true } proto = { path = "../../../proto" } +samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } From 5218640676fc91fa043d59970b2b17cb15338a54 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 14:06:19 -0700 Subject: [PATCH 25/41] Make protocol agnostic --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7b108376..5c8d8fc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ "digital-twin-model", "dtdl-parser", "in-vehicle-digital-twin", - "samples/common", + "samples/common", "samples/proto", "samples/command/consumer", "samples/command/provider", From 3367865adb630f3db72a6303ed3649262ca4caca Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 15:30:50 -0700 Subject: [PATCH 26/41] Make protocol agnostic --- samples/command/consumer/src/main.rs | 81 ++++++++++++++++++--------- samples/command/provider/src/main.rs | 15 ++--- samples/mixed/consumer/src/main.rs | 18 ++++-- samples/property/consumer/src/main.rs | 73 +++++++++++++++++------- samples/property/provider/src/main.rs | 20 ++++--- 5 files changed, 141 insertions(+), 66 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 99f2f485..3bbb8f0b 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 proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::FindByIdRequest; -use samples_common::digital_twin_operation; +use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; @@ -21,6 +21,49 @@ use uuid::Uuid; const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 const CONSUMER_AUTHORITY: &str = "[::1]:60010"; +/// Get the provider URI. +/// +/// # Arguments +/// `entity_id` - The matching entity id. +/// `protocol` - The required protocol. +/// `operations` - The required operations. +async fn get_provider_uri( + entity_id: &str, + protocol: &str, + operations: &Vec, +) -> Result { + info!("Sending a find_by_id request for entity id {entity_id} 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 + .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 provider_uri_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) { + provider_uri_option = Some(endpoint_info.uri); + break; + } + } + + if provider_uri_option.is_none() { + return Err("Did not find an endpoint that met our requirements".to_string()); + } + + let provider_uri = provider_uri_option.unwrap(); + + info!("The provider URI for entity id {entity_id} is {provider_uri}"); + + Ok(provider_uri) +} + /// Start the show notification repeater. /// /// # Arguments @@ -30,7 +73,7 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) debug!("Starting the Consumer's show notification repeater."); tokio::spawn(async move { loop { - let payload: String = String::from("The show-notification request."); + let payload: String = "The show-notification request.".to_string(); info!("Sending an invoke request on entity {} with payload '{payload} to provider URI {provider_uri}", sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); @@ -46,9 +89,8 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) let response_id = Uuid::new_v4().to_string(); let request = tonic::Request::new(InvokeRequest { - entity_id: String::from( - sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, - ), + entity_id: sdv::vehicle::cabin::infotainment::hmi::show_notification::ID + .to_string(), consumer_uri: consumer_uri.clone(), response_id, payload, @@ -81,28 +123,15 @@ 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}'"); - info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", - sdv::vehicle::cabin::infotainment::hmi::show_notification::ID); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = tonic::Request::new(FindByIdRequest { - id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), - }); - let response = client.find_by_id(request).await?; - 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 provider_uri = match response_inner.entity_access_info { - Some(content) => { - // TODO: select the right one, rather than just using the first one - content.endpoint_info_list[0].uri.clone() - } - None => { - panic!("Did not find an entity for the ShowNotification command"); - } - }; + let provider_uri = get_provider_uri( + sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, + digital_twin_protocol::GRPC, + &vec![digital_twin_operation::INVOKE.to_string()], + ) + .await + .unwrap(); - info!("The URI for the show-notification command's provider is {provider_uri}"); + info!("The URI for the ShowNotification command's provider is {provider_uri}"); let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 diff --git a/samples/command/provider/src/main.rs b/samples/command/provider/src/main.rs index 2499290f..0b1c49fd 100644 --- a/samples/command/provider/src/main.rs +++ b/samples/command/provider/src/main.rs @@ -10,6 +10,7 @@ use log::{debug, info, LevelFilter}; use parking_lot::Mutex; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use samples_common::{digital_twin_operation, digital_twin_protocol}; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; use std::net::SocketAddr; use std::sync::Arc; @@ -29,16 +30,16 @@ async fn main() -> Result<(), Box> { info!("The Provider has started."); let endpoint_info = EndpointInfo { - protocol: String::from("grpc"), - operations: vec![String::from("Get"), String::from("Set")], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), + 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 entity_access_info = EntityAccessInfo { - name: String::from("ShowNotification"), - id: String::from(sdv::vehicle::cabin::infotainment::hmi::show_notification::ID), - description: String::from("Show a notification on the HMI."), + 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![endpoint_info], }; diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 59182e58..d7ccd10f 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -72,7 +72,7 @@ fn start_show_notification_repeater(provider_uri: String, consumer_uri: String) /// Start the activate-air-conditioing repeater. /// /// # Arguments -/// `provider_uri` - The provider_uri.. +/// `provider_uri` - The provider_uri. fn start_activate_air_conditioning_repeater(provider_uri: String) { debug!("Starting the Consumer's activate-air-conditioning repeater."); tokio::spawn(async move { @@ -109,6 +109,12 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { }); } +/// Get the provider URI. +/// +/// # Arguments +/// `entity_id` - The matching entity id. +/// `protocol` - The required protocol. +/// `operations` - The required operations. async fn get_provider_uri( entity_id: &str, protocol: &str, @@ -124,9 +130,7 @@ async fn get_provider_uri( 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 an entity for the AmbientAirTemperature property"); + let entity_access_info = response_inner.entity_access_info.expect("Did not find the entity"); let mut provider_uri_option: Option = None; for endpoint_info in entity_access_info.endpoint_info_list { @@ -148,6 +152,12 @@ async fn get_provider_uri( Ok(provider_uri) } +/// Send a subscribe request. +/// +/// # Arguments +/// `provider_uri` - The provider's URI. +/// `entity_id` - The entity id. +/// `consumer_uri` - The consumer's URI. async fn send_subscribe_request( provider_uri: &str, entity_id: &str, diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index cc8c9db0..c416b42c 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -7,7 +7,7 @@ use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::FindByIdRequest; -use samples_common::digital_twin_operation; +use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; @@ -20,6 +20,49 @@ const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devsk const CONSUMER_AUTHORITY: &str = "[::1]:60010"; +/// Get the provider URI. +/// +/// # Arguments +/// `entity_id` - The matching entity id. +/// `protocol` - The required protocol. +/// `operations` - The required operations. +async fn get_provider_uri( + entity_id: &str, + protocol: &str, + operations: &Vec, +) -> Result { + info!("Sending a find_by_id request for entity id {entity_id} 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 + .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 provider_uri_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) { + provider_uri_option = Some(endpoint_info.uri); + break; + } + } + + if provider_uri_option.is_none() { + return Err("Did not find an endpoint that met our requirements".to_string()); + } + + let provider_uri = provider_uri_option.unwrap(); + + info!("The provider URI for entity id {entity_id} is {provider_uri}"); + + Ok(provider_uri) +} + #[tokio::main] async fn main() -> Result<(), Box> { // Setup logging. @@ -34,27 +77,15 @@ 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}'"); - // Obtain the DTDL for the ambient air temmpterature. - info!("Sending a find_by_id request for entity id {} to the In-Vehicle Digital Twin Service URI {IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI}", - sdv::vehicle::cabin::hvac::ambient_air_temperature::ID); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI).await?; - let request = tonic::Request::new(FindByIdRequest { - id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), - }); - let response = client.find_by_id(request).await?; - 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 provider_uri = get_provider_uri( + sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, + digital_twin_protocol::GRPC, + &vec![digital_twin_operation::SUBSCRIBE.to_string()], + ) + .await + .unwrap(); - let provider_uri = match response_inner.entity_access_info { - Some(content) => { - // TODO: select the right one, rather than just using the first one - content.endpoint_info_list[0].uri.clone() - } - None => { - panic!("Did not find an entity for the AmbientAirTemperature command"); - } - }; + info!("The URI for the AmbientAirTemperature property's provider is {provider_uri}"); let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 diff --git a/samples/property/provider/src/main.rs b/samples/property/provider/src/main.rs index 7a996917..c26a1ec8 100644 --- a/samples/property/provider/src/main.rs +++ b/samples/property/provider/src/main.rs @@ -10,6 +10,7 @@ use log::{debug, info, warn, LevelFilter}; use parking_lot::{Mutex, MutexGuard}; use proto::digital_twin::digital_twin_client::DigitalTwinClient; use proto::digital_twin::{EndpointInfo, EntityAccessInfo, RegisterRequest}; +use samples_common::{digital_twin_operation, digital_twin_protocol}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_client::DigitalTwinConsumerClient; use samples_proto::sample_grpc::v1::digital_twin_consumer::PublishRequest; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_server::DigitalTwinProviderServer; @@ -60,7 +61,7 @@ fn start_ambient_air_temperature_data_stream(subscription_map: Arc Result<(), Box> { info!("The Provider has started."); let endpoint_info = EndpointInfo { - protocol: String::from("grpc"), - operations: vec![String::from("Subscribe"), String::from("Unsubscribe")], - uri: String::from("http://[::1]:40010"), // Devskim: ignore DS137138 - context: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), + 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 entity_access_info = EntityAccessInfo { - name: String::from("AmbientAirTemperature"), - id: String::from(sdv::vehicle::cabin::hvac::ambient_air_temperature::ID), - description: String::from("The immediate surroundings air temperature (in Fahrenheit)."), + 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], }; From c62ff4c6af7f29401698f8b51c17d9b1628c4e9a Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 15:40:42 -0700 Subject: [PATCH 27/41] Make protocol agnostic --- samples/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 561dcebf..516939f7 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -21,7 +21,7 @@ pub mod digital_twin_protocol { /// # Arguments /// `subset` - The provided subset. /// `superset` - The provided superset. -pub fn is_subset(subset: &Vec, superset: &Vec) -> bool { +pub fn is_subset(subset: &[String], superset: &[String]) -> bool { subset.iter().all(|subset_member| { superset.iter().any(|supserset_member| subset_member == supserset_member) }) From 3a2b24909748c48dd0fa8da8c8769a191b2ab90c Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 15:44:23 -0700 Subject: [PATCH 28/41] Make protocol agnostic --- in-vehicle-digital-twin/src/digitaltwin_impl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 60266e94..8b061298 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -175,6 +175,7 @@ mod digitaltwin_impl_tests { ); 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] From 207099dd3d269b085746af11c2deaeaf469eba3d Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 15:55:38 -0700 Subject: [PATCH 29/41] Make protocol agnostic --- samples/common/src/lib.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 516939f7..07006222 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -33,25 +33,37 @@ mod ibeji_common_tests { #[test] fn is_subset_test() { - assert!(is_subset(&vec!(), &vec!())); - assert!(is_subset(&vec!(), &vec!("one".to_string()))); - assert!(is_subset(&vec!(), &vec!("one".to_string(), "two".to_string()))); - assert!(is_subset(&vec!("one".to_string()), &vec!("one".to_string(), "two".to_string()))); assert!(is_subset( - &vec!("one".to_string(), "two".to_string()), - &vec!("one".to_string(), "two".to_string()) + &[], + &[] + )); + 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( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!("one".to_string(), "two".to_string()) + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string(), "two".to_string()] )); assert!(!is_subset( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!("one".to_string()) + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string()] )); assert!(!is_subset( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!() + &["one".to_string(), "two".to_string(), "three".to_string()], + &[] )); } } From ef415114e05a80a418cca3cb232a92cf239a6810 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 16:15:31 -0700 Subject: [PATCH 30/41] Make protocol agnostic --- samples/common/src/lib.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 07006222..088ee193 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -21,7 +21,7 @@ pub mod digital_twin_protocol { /// # Arguments /// `subset` - The provided subset. /// `superset` - The provided superset. -pub fn is_subset(subset: &[String], superset: &[String]) -> bool { +pub fn is_subset(subset: &Vec, superset: &Vec) -> bool { subset.iter().all(|subset_member| { superset.iter().any(|supserset_member| subset_member == supserset_member) }) @@ -34,36 +34,36 @@ mod ibeji_common_tests { #[test] fn is_subset_test() { assert!(is_subset( - &[], - &[] + &vec!(), + &vec!() )); assert!(is_subset( - &[], - &["one".to_string()] + &vec!(), + &vec!("one".to_string()) )); assert!(is_subset( - &[], - &["one".to_string(), "two".to_string()] + &vec!(), + &vec!("one".to_string(), "two".to_string()) )); assert!(is_subset( - &["one".to_string()], - &["one".to_string(), "two".to_string()] + &vec!("one".to_string()), + &vec!("one".to_string(), "two".to_string()) )); assert!(is_subset( - &["one".to_string(), "two".to_string()], - &["one".to_string(), "two".to_string()] + &vec!("one".to_string(), "two".to_string()), + &vec!("one".to_string(), "two".to_string()) )); assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &["one".to_string(), "two".to_string()] + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!("one".to_string(), "two".to_string()) )); assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &["one".to_string()] + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!("one".to_string()) )); assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &[] + &vec!("one".to_string(), "two".to_string(), "three".to_string()), + &vec!() )); } } From 88ba9444a52f627766efb2add5f1b9d0bc5984fc Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Fri, 12 May 2023 16:23:49 -0700 Subject: [PATCH 31/41] Make protocol agnostic --- .../src/digitaltwin_impl.rs | 6 ++++-- samples/common/src/lib.rs | 20 ++++--------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 8b061298..5f991041 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -174,8 +174,10 @@ mod digitaltwin_impl_tests { "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 + assert_eq! + (response_entity_access_info.endpoint_info_list[0].uri, + "http://[::1]:40010" // Devskim: ignore DS137138 + ); } #[tokio::test] diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 088ee193..561dcebf 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -33,22 +33,10 @@ mod ibeji_common_tests { #[test] fn is_subset_test() { - assert!(is_subset( - &vec!(), - &vec!() - )); - assert!(is_subset( - &vec!(), - &vec!("one".to_string()) - )); - assert!(is_subset( - &vec!(), - &vec!("one".to_string(), "two".to_string()) - )); - assert!(is_subset( - &vec!("one".to_string()), - &vec!("one".to_string(), "two".to_string()) - )); + assert!(is_subset(&vec!(), &vec!())); + assert!(is_subset(&vec!(), &vec!("one".to_string()))); + assert!(is_subset(&vec!(), &vec!("one".to_string(), "two".to_string()))); + assert!(is_subset(&vec!("one".to_string()), &vec!("one".to_string(), "two".to_string()))); assert!(is_subset( &vec!("one".to_string(), "two".to_string()), &vec!("one".to_string(), "two".to_string()) From fad560bd83d92cdf8f99371d18affcaa9e72fb81 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 14 May 2023 17:57:09 -0700 Subject: [PATCH 32/41] Make protocol agnostic --- samples/command/consumer/src/main.rs | 6 +++--- samples/common/src/lib.rs | 9 ++++++++- samples/mixed/consumer/src/main.rs | 14 +++++++------- samples/property/consumer/src/main.rs | 6 +++--- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 3bbb8f0b..2ebf4880 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -30,7 +30,7 @@ const CONSUMER_AUTHORITY: &str = "[::1]:60010"; async fn get_provider_uri( entity_id: &str, protocol: &str, - operations: &Vec, + 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_DIGITAL_TWIN_SERVICE_URI}"); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI) @@ -47,7 +47,7 @@ async fn get_provider_uri( let mut provider_uri_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) { + if endpoint_info.protocol == protocol && is_subset(operations, endpoint_info.operations.as_slice()) { provider_uri_option = Some(endpoint_info.uri); break; } @@ -126,7 +126,7 @@ async fn main() -> Result<(), Box> { let provider_uri = get_provider_uri( sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::INVOKE.to_string()], + vec![digital_twin_operation::INVOKE.to_string()].as_slice(), ) .await .unwrap(); diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 561dcebf..3b7ee3a0 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -21,11 +21,18 @@ pub mod digital_twin_protocol { /// # Arguments /// `subset` - The provided subset. /// `superset` - The provided superset. -pub fn is_subset(subset: &Vec, superset: &Vec) -> bool { +pub fn is_subset(subset: &[String], superset: &[String]) -> bool { subset.iter().all(|subset_member| { superset.iter().any(|supserset_member| subset_member == supserset_member) }) } +/* +pub fn is_subset(subset: Vec, superset: Vec) -> bool { + subset.iter().all(|subset_member| { + superset.iter().any(|supserset_member| subset_member == supserset_member) + }) +} + */ #[cfg(test)] mod ibeji_common_tests { diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index d7ccd10f..01c4950d 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -118,7 +118,7 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { async fn get_provider_uri( entity_id: &str, protocol: &str, - operations: &Vec, + 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_DIGITAL_TWIN_SERVICE_URI}"); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI) @@ -135,7 +135,7 @@ async fn get_provider_uri( let mut provider_uri_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) { + if endpoint_info.protocol == protocol && is_subset(operations, &endpoint_info.operations.as_slice()) { provider_uri_option = Some(endpoint_info.uri); break; } @@ -191,7 +191,7 @@ async fn main() -> Result<(), Box> { let show_notification_command_provider_uri = get_provider_uri( sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::INVOKE.to_string()], + vec![digital_twin_operation::INVOKE.to_string()].as_slice(), ) .await .unwrap(); @@ -199,7 +199,7 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_property_provider_uri = get_provider_uri( sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::SUBSCRIBE.to_string()], + vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), ) .await .unwrap(); @@ -207,10 +207,10 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_uri = get_provider_uri( sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, digital_twin_protocol::GRPC, - &vec![ + vec![ digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::SET.to_string(), - ], + ].as_slice(), ) .await .unwrap(); @@ -218,7 +218,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_uri = get_provider_uri( sdv::vehicle::obd::hybrid_battery_remaining::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::SUBSCRIBE.to_string()], + vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), ) .await .unwrap(); diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index c416b42c..e25bc669 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -29,7 +29,7 @@ const CONSUMER_AUTHORITY: &str = "[::1]:60010"; async fn get_provider_uri( entity_id: &str, protocol: &str, - operations: &Vec, + 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_DIGITAL_TWIN_SERVICE_URI}"); let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI) @@ -46,7 +46,7 @@ async fn get_provider_uri( let mut provider_uri_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) { + if endpoint_info.protocol == protocol && is_subset(operations, &endpoint_info.operations.as_slice()) { provider_uri_option = Some(endpoint_info.uri); break; } @@ -80,7 +80,7 @@ async fn main() -> Result<(), Box> { let provider_uri = get_provider_uri( sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::SUBSCRIBE.to_string()], + &vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), ) .await .unwrap(); From b94a898ad15de86933cb14264322184085429825 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 14 May 2023 19:39:53 -0700 Subject: [PATCH 33/41] Make protocol agnostic --- samples/common/src/lib.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 3b7ee3a0..24490648 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -40,25 +40,37 @@ mod ibeji_common_tests { #[test] fn is_subset_test() { - assert!(is_subset(&vec!(), &vec!())); - assert!(is_subset(&vec!(), &vec!("one".to_string()))); - assert!(is_subset(&vec!(), &vec!("one".to_string(), "two".to_string()))); - assert!(is_subset(&vec!("one".to_string()), &vec!("one".to_string(), "two".to_string()))); assert!(is_subset( - &vec!("one".to_string(), "two".to_string()), - &vec!("one".to_string(), "two".to_string()) + &[], + &[] + )); + 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( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!("one".to_string(), "two".to_string()) + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string(), "two".to_string()] )); assert!(!is_subset( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!("one".to_string()) + &["one".to_string(), "two".to_string(), "three".to_string()], + &["one".to_string()] )); assert!(!is_subset( - &vec!("one".to_string(), "two".to_string(), "three".to_string()), - &vec!() + &["one".to_string(), "two".to_string(), "three".to_string()], + &[] )); } } From 737fa67a3dd22a44ea2503209d1be86628cb4c11 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 14 May 2023 19:47:18 -0700 Subject: [PATCH 34/41] Make protocol agnostic --- samples/property/consumer/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index e25bc669..a04d756d 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -46,7 +46,7 @@ async fn get_provider_uri( let mut provider_uri_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()) { + if endpoint_info.protocol == protocol && is_subset(operations, endpoint_info.operations.as_slice()) { provider_uri_option = Some(endpoint_info.uri); break; } @@ -80,7 +80,7 @@ async fn main() -> Result<(), Box> { let provider_uri = get_provider_uri( sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, - &vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), + &[digital_twin_operation::SUBSCRIBE.to_string()], ) .await .unwrap(); From b171c8ac0c98408d71d4ae712b849b3400fc3cb2 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 14 May 2023 19:57:09 -0700 Subject: [PATCH 35/41] Make protocol agnostic --- samples/command/consumer/src/main.rs | 2 +- samples/mixed/consumer/src/main.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 2ebf4880..e08a07d6 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -126,7 +126,7 @@ async fn main() -> Result<(), Box> { let provider_uri = get_provider_uri( sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, - vec![digital_twin_operation::INVOKE.to_string()].as_slice(), + &[digital_twin_operation::INVOKE.to_string()], ) .await .unwrap(); diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 01c4950d..9f3e497c 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -135,7 +135,7 @@ async fn get_provider_uri( let mut provider_uri_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()) { + if endpoint_info.protocol == protocol && is_subset(operations, endpoint_info.operations.as_slice()) { provider_uri_option = Some(endpoint_info.uri); break; } @@ -191,7 +191,7 @@ async fn main() -> Result<(), Box> { let show_notification_command_provider_uri = get_provider_uri( sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, - vec![digital_twin_operation::INVOKE.to_string()].as_slice(), + &[digital_twin_operation::INVOKE.to_string()], ) .await .unwrap(); @@ -199,7 +199,7 @@ async fn main() -> Result<(), Box> { let ambient_air_temperature_property_provider_uri = get_provider_uri( sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, - vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), + &[digital_twin_operation::SUBSCRIBE.to_string()], ) .await .unwrap(); @@ -207,10 +207,10 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_uri = get_provider_uri( sdv::vehicle::cabin::hvac::is_air_conditioning_active::ID, digital_twin_protocol::GRPC, - vec![ + &[ digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::SET.to_string(), - ].as_slice(), + ], ) .await .unwrap(); @@ -218,7 +218,7 @@ async fn main() -> Result<(), Box> { let hybrid_battery_remaining_property_uri = get_provider_uri( sdv::vehicle::obd::hybrid_battery_remaining::ID, digital_twin_protocol::GRPC, - vec![digital_twin_operation::SUBSCRIBE.to_string()].as_slice(), + &[digital_twin_operation::SUBSCRIBE.to_string()], ) .await .unwrap(); From 8c5202f04e5de33f5f8aa767b75d1b25176ea204 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Sun, 14 May 2023 20:22:13 -0700 Subject: [PATCH 36/41] Make protocol agnostic --- .../src/digitaltwin_impl.rs | 6 ++--- samples/command/consumer/src/main.rs | 4 ++- samples/common/src/lib.rs | 25 ++++--------------- samples/mixed/consumer/src/main.rs | 9 +++---- samples/property/consumer/src/main.rs | 4 ++- 5 files changed, 18 insertions(+), 30 deletions(-) diff --git a/in-vehicle-digital-twin/src/digitaltwin_impl.rs b/in-vehicle-digital-twin/src/digitaltwin_impl.rs index 5f991041..2565f986 100644 --- a/in-vehicle-digital-twin/src/digitaltwin_impl.rs +++ b/in-vehicle-digital-twin/src/digitaltwin_impl.rs @@ -174,9 +174,9 @@ mod digitaltwin_impl_tests { "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 + assert_eq!( + response_entity_access_info.endpoint_info_list[0].uri, + "http://[::1]:40010" // Devskim: ignore DS137138 ); } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index e08a07d6..22995633 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -47,7 +47,9 @@ async fn get_provider_uri( let mut provider_uri_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()) { + if endpoint_info.protocol == protocol + && is_subset(operations, endpoint_info.operations.as_slice()) + { provider_uri_option = Some(endpoint_info.uri); break; } diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 24490648..827db91f 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -40,22 +40,10 @@ mod ibeji_common_tests { #[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(&[], &[])); + 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()] @@ -68,9 +56,6 @@ mod ibeji_common_tests { &["one".to_string(), "two".to_string(), "three".to_string()], &["one".to_string()] )); - assert!(!is_subset( - &["one".to_string(), "two".to_string(), "three".to_string()], - &[] - )); + assert!(!is_subset(&["one".to_string(), "two".to_string(), "three".to_string()], &[])); } } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 9f3e497c..96c91a71 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -135,7 +135,9 @@ async fn get_provider_uri( let mut provider_uri_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()) { + if endpoint_info.protocol == protocol + && is_subset(operations, endpoint_info.operations.as_slice()) + { provider_uri_option = Some(endpoint_info.uri); break; } @@ -207,10 +209,7 @@ async fn main() -> Result<(), Box> { let is_air_conditioning_active_property_uri = get_provider_uri( 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(), - ], + &[digital_twin_operation::SUBSCRIBE.to_string(), digital_twin_operation::SET.to_string()], ) .await .unwrap(); diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index a04d756d..bccf843d 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -46,7 +46,9 @@ async fn get_provider_uri( let mut provider_uri_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()) { + if endpoint_info.protocol == protocol + && is_subset(operations, endpoint_info.operations.as_slice()) + { provider_uri_option = Some(endpoint_info.uri); break; } From 31f143ff4f97415efd95716eb13aac53fd566aea Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 15 May 2023 14:01:27 -0700 Subject: [PATCH 37/41] Make protocol agnostic --- samples/command/consumer/Cargo.toml | 1 - samples/command/consumer/src/main.rs | 54 ++----------------- samples/common/Cargo.toml | 5 ++ samples/common/src/lib.rs | 56 +++++++++++++++++--- samples/mixed/consumer/Cargo.toml | 2 +- samples/mixed/consumer/src/main.rs | 75 +++++++-------------------- samples/property/consumer/src/main.rs | 54 ++----------------- 7 files changed, 86 insertions(+), 161 deletions(-) diff --git a/samples/command/consumer/Cargo.toml b/samples/command/consumer/Cargo.toml index 7ae856cc..a9d4706d 100644 --- a/samples/command/consumer/Cargo.toml +++ b/samples/command/consumer/Cargo.toml @@ -16,7 +16,6 @@ iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } log = { workspace = true } prost = { workspace = true } -proto = { path = "../../../proto" } samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } diff --git a/samples/command/consumer/src/main.rs b/samples/command/consumer/src/main.rs index 22995633..e053c118 100644 --- a/samples/command/consumer/src/main.rs +++ b/samples/command/consumer/src/main.rs @@ -7,9 +7,7 @@ mod consumer_impl; use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::digital_twin::digital_twin_client::DigitalTwinClient; -use proto::digital_twin::FindByIdRequest; -use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; +use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::InvokeRequest; @@ -21,51 +19,6 @@ use uuid::Uuid; const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devskim: ignore DS137138 const CONSUMER_AUTHORITY: &str = "[::1]:60010"; -/// Get the provider URI. -/// -/// # Arguments -/// `entity_id` - The matching entity id. -/// `protocol` - The required protocol. -/// `operations` - The required operations. -async fn get_provider_uri( - 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_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_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 provider_uri_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()) - { - provider_uri_option = Some(endpoint_info.uri); - break; - } - } - - if provider_uri_option.is_none() { - return Err("Did not find an endpoint that met our requirements".to_string()); - } - - let provider_uri = provider_uri_option.unwrap(); - - info!("The provider URI for entity id {entity_id} is {provider_uri}"); - - Ok(provider_uri) -} - /// Start the show notification repeater. /// /// # Arguments @@ -125,7 +78,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_uri = get_provider_uri( + let provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, sdv::vehicle::cabin::infotainment::hmi::show_notification::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::INVOKE.to_string()], @@ -133,6 +87,8 @@ async fn main() -> Result<(), Box> { .await .unwrap(); + 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 diff --git a/samples/common/Cargo.toml b/samples/common/Cargo.toml index 01c4760f..9f3ee0df 100644 --- a/samples/common/Cargo.toml +++ b/samples/common/Cargo.toml @@ -7,3 +7,8 @@ name = "samples_common" version = "0.1.0" edition = "2021" license = "MIT" + +[dependencies] +log = { workspace = true } +proto = { path = "../../proto" } +tonic = { workspace = true } \ No newline at end of file diff --git a/samples/common/src/lib.rs b/samples/common/src/lib.rs index 827db91f..6c44676d 100644 --- a/samples/common/src/lib.rs +++ b/samples/common/src/lib.rs @@ -2,6 +2,10 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +use log::{debug, info}; +use proto::digital_twin::digital_twin_client::DigitalTwinClient; +use proto::digital_twin::{EndpointInfo, FindByIdRequest}; + /// Supported digital twin operations. pub mod digital_twin_operation { pub const GET: &str = "Get"; @@ -26,13 +30,53 @@ pub fn is_subset(subset: &[String], superset: &[String]) -> bool { superset.iter().any(|supserset_member| subset_member == supserset_member) }) } -/* -pub fn is_subset(subset: Vec, superset: Vec) -> 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) } - */ #[cfg(test)] mod ibeji_common_tests { diff --git a/samples/mixed/consumer/Cargo.toml b/samples/mixed/consumer/Cargo.toml index 414430f0..783834ea 100644 --- a/samples/mixed/consumer/Cargo.toml +++ b/samples/mixed/consumer/Cargo.toml @@ -16,7 +16,7 @@ iref = { workspace = true } json-ld = { git = "https://github.com/blast-hardcheese/json-ld", branch = "resolve-issue-40" } log = { workspace = true } prost = { workspace = true } -proto = { path = "../../../proto" } +# proto = { path = "../../../proto" } samples_common = { path = "../../common" } samples_proto = { path = "../../proto" } serde_json = { workspace = true } diff --git a/samples/mixed/consumer/src/main.rs b/samples/mixed/consumer/src/main.rs index 96c91a71..f7e06c29 100644 --- a/samples/mixed/consumer/src/main.rs +++ b/samples/mixed/consumer/src/main.rs @@ -7,9 +7,7 @@ mod consumer_impl; use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, warn, LevelFilter}; -use proto::digital_twin::digital_twin_client::DigitalTwinClient; -use proto::digital_twin::FindByIdRequest; -use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; +use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::{ @@ -109,51 +107,6 @@ fn start_activate_air_conditioning_repeater(provider_uri: String) { }); } -/// Get the provider URI. -/// -/// # Arguments -/// `entity_id` - The matching entity id. -/// `protocol` - The required protocol. -/// `operations` - The required operations. -async fn get_provider_uri( - 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_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_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 provider_uri_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()) - { - provider_uri_option = Some(endpoint_info.uri); - break; - } - } - - if provider_uri_option.is_none() { - return Err("Did not find an endpoint that met our requirements".to_string()); - } - - let provider_uri = provider_uri_option.unwrap(); - - info!("The provider URI for entity id {entity_id} is {provider_uri}"); - - Ok(provider_uri) -} - /// Send a subscribe request. /// /// # Arguments @@ -190,37 +143,49 @@ 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_uri = get_provider_uri( + let show_notification_command_provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, 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_uri = get_provider_uri( + let ambient_air_temperature_property_provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, 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_uri = get_provider_uri( + let is_air_conditioning_active_property_provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, 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_uri = get_provider_uri( + let hybrid_battery_remaining_property_provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, 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; let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 @@ -232,20 +197,20 @@ async fn main() -> Result<(), Box> { .await?; send_subscribe_request( - &is_air_conditioning_active_property_uri, + &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_uri, + &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_uri); + start_activate_air_conditioning_repeater(is_air_conditioning_active_property_provider_uri); start_show_notification_repeater( show_notification_command_provider_uri.clone(), diff --git a/samples/property/consumer/src/main.rs b/samples/property/consumer/src/main.rs index bccf843d..bc425a5b 100644 --- a/samples/property/consumer/src/main.rs +++ b/samples/property/consumer/src/main.rs @@ -5,9 +5,7 @@ use digital_twin_model::sdv_v1 as sdv; use env_logger::{Builder, Target}; use log::{debug, info, LevelFilter}; -use proto::digital_twin::digital_twin_client::DigitalTwinClient; -use proto::digital_twin::FindByIdRequest; -use samples_common::{digital_twin_operation, digital_twin_protocol, is_subset}; +use samples_common::{digital_twin_operation, digital_twin_protocol, find_provider_endpoint}; use samples_proto::sample_grpc::v1::digital_twin_consumer::digital_twin_consumer_server::DigitalTwinConsumerServer; use samples_proto::sample_grpc::v1::digital_twin_provider::digital_twin_provider_client::DigitalTwinProviderClient; use samples_proto::sample_grpc::v1::digital_twin_provider::SubscribeRequest; @@ -20,51 +18,6 @@ const IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI: &str = "http://[::1]:50010"; // Devsk const CONSUMER_AUTHORITY: &str = "[::1]:60010"; -/// Get the provider URI. -/// -/// # Arguments -/// `entity_id` - The matching entity id. -/// `protocol` - The required protocol. -/// `operations` - The required operations. -async fn get_provider_uri( - 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_DIGITAL_TWIN_SERVICE_URI}"); - let mut client = DigitalTwinClient::connect(IN_VEHICLE_DIGITAL_TWIN_SERVICE_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 provider_uri_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()) - { - provider_uri_option = Some(endpoint_info.uri); - break; - } - } - - if provider_uri_option.is_none() { - return Err("Did not find an endpoint that met our requirements".to_string()); - } - - let provider_uri = provider_uri_option.unwrap(); - - info!("The provider URI for entity id {entity_id} is {provider_uri}"); - - Ok(provider_uri) -} - #[tokio::main] async fn main() -> Result<(), Box> { // Setup logging. @@ -79,7 +32,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_uri = get_provider_uri( + let provider_endpoint_info = find_provider_endpoint( + IN_VEHICLE_DIGITAL_TWIN_SERVICE_URI, sdv::vehicle::cabin::hvac::ambient_air_temperature::ID, digital_twin_protocol::GRPC, &[digital_twin_operation::SUBSCRIBE.to_string()], @@ -87,6 +41,8 @@ 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}"); let consumer_uri = format!("http://{CONSUMER_AUTHORITY}"); // Devskim: ignore DS137138 From e23563e0bdd1a14b19a8ca8b1da8900a8c8ca368 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 15 May 2023 15:20:02 -0700 Subject: [PATCH 38/41] Make protocol agnostic --- docs/design/README.md | 76 +++++++------------ docs/design/diagrams/findbyid_sequence.puml | 4 +- docs/design/diagrams/findbyid_sequence.svg | 17 +++-- docs/design/diagrams/ibeji_component.puml | 7 +- docs/design/diagrams/ibeji_component.svg | 27 +++---- docs/design/diagrams/invoke_sequence.puml | 2 +- docs/design/diagrams/invoke_sequence.svg | 22 +++++- docs/design/diagrams/publish_sequence.puml | 2 +- docs/design/diagrams/publish_sequence.svg | 15 ++-- docs/design/diagrams/register_sequence.puml | 2 +- docs/design/diagrams/register_sequence.svg | 15 ++-- docs/design/diagrams/respond_sequence.puml | 2 +- docs/design/diagrams/respond_sequence.svg | 22 +++++- docs/design/diagrams/subscribe_sequence.puml | 2 +- docs/design/diagrams/subscribe_sequence.svg | 15 ++-- .../src/digitaltwin_impl.rs | 16 +--- proto/digital_twin/v1/digital_twin.proto | 11 --- 17 files changed, 135 insertions(+), 122 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index 578cf60c..ccec3fc6 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -17,15 +17,15 @@ Please note that the initial Ibeji implementation is a proof-of-concept. We woul Ibeji has three main architectural concepts: -- Consumer -- Provider +- Digital Twin Consumer +- Digital Twin Provider - In-Vehicle Digital Twin Service -The first Ibeji architectural concept that we will introduce is the Consumer. A Consumer is a software entity that utilizes Ibeji to interface with the digital representation of the In-Vehicle hardware components. +The first Ibeji architectural concept that we will introduce is the Digital Twin Consumer. A Digital Twin Consumer is a software entity that utilizes Ibeji to interface with the digital representation of the In-Vehicle hardware components. -Another Ibeji architectural concept is the Provider. A Provider is the access point to some/all of the vehicle's hardware resources. A Provider registers itself with the In-Vehicle Digital Twin Service. Once registered, the In-Vehicle Digital Twin Service can make the resources available to Consumers. Each resource includes meta data that allow Consumers to understand the semantics of the resource and know how to interact with it. The In-Vehicle Digital Twin Service supports multiple simultaneous Providers and internally resolves overlapping resources offered by multiple Providers. These overlaps offer multiple options for interacting with a resource and can improve the resource's availability (by supporting multiple access paths). A Provider must support a Provider interface that enables access to resource data feeds. +Another Ibeji architectural concept is the Digital Twin Provider. A Digital Twin Provider is the access point to some/all of the vehicle's hardware resources. A Digital Twin Provider registers itself with the In-Vehicle Digital Twin Service. Once registered, the In-Vehicle Digital Twin Service can make the resources available to Digital Twin Consumers. Each resource includes meta data so that DIgital Twin Consumers know how to interact with it. The In-Vehicle Digital Twin Service supports multiple simultaneous Digital Twin Providers and internally resolves overlapping resources offered by multiple Digital Twin Providers. These overlaps offer multiple options for interacting with a resource and can improve the resource's availability (by supporting multiple access paths). -In the middle is the In-Vehicle Digital Twin Service. It exports a query interface that enables Consumers to discover the vehicle's resources and provides the details necessary to use those resources. The In-Vehicle Digital Twin Service has an interface that allows Providers to dynamically register and unregister resources. +In the middle is the In-Vehicle Digital Twin Service. It exports a query interface that enables Digital Twin Consumers to discover the vehicle's resources and provides the details necessary to use those resources. The In-Vehicle Digital Twin Service has an interface that allows Digital Twin Providers to dynamically register their resources. Below is the component diagram for Ibeji. @@ -33,48 +33,41 @@ Below is the component diagram for Ibeji. ## DTDL -Fundamental to the Ibeji solution is its use of Digital Twin Definition Language [DTDL](https://github.com/Azure/opendigitaltwins-dtdl) to identify and specify each of the vehicle's resources, and to provide the metadata needed to interact the resource. +Fundamental to the Ibeji solution is its use of Digital Twin Definition Language [DTDL](https://github.com/Azure/opendigitaltwins-dtdl) to identify and specify each of the vehicle's resources. This initial contribution does not try to arrange the resources into a hierarchy or into a graph. It is intended that some future update will enable this capability. -DTDL can identify and specify each of the resources. DTDL allows additional metadata to be associated with each of the resources, specifically the endpoint that can be used to interact with that resource. Below is an example for the AmbientAirTemperature property. You can see that the resource has the "RemotelyAccessible" type, which allows it to specify remote access metadata. The remote_access element utilizes an "Endpoint" type to specify the resource's endpoint and the supported operations. +DTDL can identify and specify each of the resources. Below is an example for the AmbientAirTemperature property. ```uml { - "@context": ["dtmi:dtdl:context;2", "dtmi:sdv:context;3"], + "@context": ["dtmi:dtdl:context;2"], "@type": "Interface", - "@id": "dtmi:org:eclipse:sdv:interface:cabin:AmbientAirTemperature;1", + "@id": "dtmi:sdv:Vehicle:Cabin:HVAC;1", "contents": [ { - "@type": ["Property", "Temperature", "RemotelyAccessible"], - "@id": "dtmi:org:eclipse:sdv:property:cabin:AmbientAirTemperature;1", + "@type": ["Property", "Temperature"], + "@id": "dtmi:sdv:Vehicle:Cabin:HVAC:AmbientAirTemperature;1", "name": "Cabin_AmbientAirTemperature", "description": "The immediate surroundings air temperature (in Fahrenheit).", - "schema": "double", - "unit": "degreeFahrenheit", - "remote_access": [ - { - "@type": "Endpoint", - "uri": "http://[::1]:40010", - "operations": [ "Get", "Set", "Subscribe", "Unsubscribe" ] - } - ] + "schema": "integer", + "unit": "degreeFahrenheit" } ] } ``` -The DTDL must use the standard dtmi dtdl context. It must also use the dtmi sdv context, which provides the definitions for the RemotelyAccessible type and the remote_access element. +The DTDL must use the standard dtmi dtdl context. ## In-Vehicle Digital Twin Service ### In-Vehicle Digital Twin Service Overview -The initial In-Vehicle Digital Twin Service will provide the functionality needed by the proof-of-concept. On the Provider side, this initial contribution supports only a single Provider registering its DTDL. On the Consumer side, there is a simplified query api, and the ability to subscribe to a provided hardware resource data feed and to invoke commands on provided hardware resources. +The initial In-Vehicle Digital Twin Service will provide the functionality needed by the proof-of-concept. On the Provider side, this initial contribution supports only a single Provider registering its DTDL. On the Consumer side, there is a simplified query api, and the ability to subscribe to a provided hardware resource data feed and to invoke a command on a provided hardware resource. ### Interfaces -The initial In-Vehicle Digital Twin Service supports both Providers and Consumers with a gRPC interface. +The initial In-Vehicle Digital Twin Service supports both Providers and Consumers. ### Activities @@ -98,19 +91,19 @@ The initial Providers will implement basic resources - the AmbientAirTemperature ### Interfaces -A Provider supports a gRPC interface for subscribing to resource's data feeds, unsubscribing from a resource's data feed, requesting a resource's value, setting a resource's value and invoking a command. +A Provider supports an interface for subscribing to resource's data feeds, requesting a resource's value, setting a resource's value and invoking a command. ### Activities #### Subscribe -Below is the sequence diagram for the Subscribe activity. The Provider's endpoint details are exported by the Provider as DTDL to the Digital Twin Service. +Below is the sequence diagram for the Subscribe activity. ![Sequence Diagram](diagrams/subscribe_sequence.svg) #### Invoke -Below is the sequence diagram for the Invoke activity. The Provider's endpoint details are exported by the Provider as DTDL to the Digital Twin Service. +Below is the sequence diagram for the Invoke activity. ![Sequence Diagram](diagrams/invoke_sequence.svg) @@ -122,7 +115,7 @@ The initial Consumers will provide the functionality needed by the proof-of-conc Interfaces -A Consumer supports a gRPC interface that is the callback/notification endpoint for subscribed-to data feeds. +A Consumer supports an interface that is the callback/notification endpoint for subscribed-to data feeds. Activities @@ -138,7 +131,7 @@ Below is the sequence diagram for the Respond activity. ![Sequence Diagram](diagrams/respond_sequence.svg) -## Appendix A – Provider gRPC Interface +## Appendix A – Digital Twin Provider Interface ### Subscribe @@ -199,18 +192,19 @@ Invoke a command. #### Request - entity_id - The command's id. -- uri - The uri for the endpoint where the command's response should be delivered. +- consumer_uri - The uri for the endpoint where the command's response should be delivered. +- response_id - The id that the invoker of the command provided for the response. - payload - The command's request payload. #### Response - No response. -## Appendix B – Digital Twin gRPC Interface +## Appendix B – Digital Twin Interface ### FindById -Find an entity's DTDL. +Find an entity's access information. #### Request @@ -218,33 +212,21 @@ Find an entity's DTDL. #### Response -- dtdl - The resource's DTDL. +- entity_access_info - The entity's access information. ### Register -Register one or more entities. - -#### Request - -- dtdl - The DTDL that represents the entities. - -#### Response - -- No response. - -### Unregister - -Unregister an entity. +Register one or more entities access information. #### Request -- id - The resource's id. +- entity_access_info_list - A list of entity access infromation. #### Response - No response. -## Appendix C – Consumer gRPC Interface +## Appendix C – Digital Twin Consumer Interface ### Publish diff --git a/docs/design/diagrams/findbyid_sequence.puml b/docs/design/diagrams/findbyid_sequence.puml index 27ee87af..64cbd179 100644 --- a/docs/design/diagrams/findbyid_sequence.puml +++ b/docs/design/diagrams/findbyid_sequence.puml @@ -3,7 +3,7 @@ participant "In-Vehicle Digital Twin Service" participant "Consumer" -"Consumer" -> "In-Vehicle Digital Twin Service" : FindById - request (id) -"In-Vehicle Digital Twin Service" --> "Consumer" : FindById - response (dtdl) +"Consumer" -> "In-Vehicle Digital Twin Service" : FindById - request (entity id) +"In-Vehicle Digital Twin Service" --> "Consumer" : FindById - response (entity access info) @enduml diff --git a/docs/design/diagrams/findbyid_sequence.svg b/docs/design/diagrams/findbyid_sequence.svg index 8a57da19..293be430 100644 --- a/docs/design/diagrams/findbyid_sequence.svg +++ b/docs/design/diagrams/findbyid_sequence.svg @@ -1,16 +1,21 @@ -In-Vehicle Digital Twin ServiceIn-Vehicle Digital Twin ServiceConsumerConsumerFindById - request (id)FindById - response (dtdl)ConsumerIn-Vehicle Digital Twin ServiceProviderConsumerDigital TwinProviderProviderConsumerIn-Vehicle Digital Twin ServiceProviderDigitalTwinConsumerInterfaceDigitalTwinInterfaceDigitalTwinProviderInterface \ No newline at end of file +ProviderProviderConsumerConsumerInvoke - request (entity id, consumer uri, response id, payload) \ No newline at end of file diff --git a/docs/design/diagrams/publish_sequence.puml b/docs/design/diagrams/publish_sequence.puml index 510ca335..695a9b31 100644 --- a/docs/design/diagrams/publish_sequence.puml +++ b/docs/design/diagrams/publish_sequence.puml @@ -3,6 +3,6 @@ participant "Provider" participant "Consumer" -"Provider" -> "Consumer" : Publish - request (id, value) +"Provider" -> "Consumer" : Publish - request (entity id, value) @enduml diff --git a/docs/design/diagrams/publish_sequence.svg b/docs/design/diagrams/publish_sequence.svg index 3335d7bf..ecc9c5cf 100644 --- a/docs/design/diagrams/publish_sequence.svg +++ b/docs/design/diagrams/publish_sequence.svg @@ -1,15 +1,20 @@ -ProviderProviderConsumerConsumerPublish - request (id, value) \ No newline at end of file +ProviderProviderConsumerConsumerRespond - request (entity id, response id, payload) \ No newline at end of file diff --git a/docs/design/diagrams/subscribe_sequence.puml b/docs/design/diagrams/subscribe_sequence.puml index a95f7a91..135191c4 100644 --- a/docs/design/diagrams/subscribe_sequence.puml +++ b/docs/design/diagrams/subscribe_sequence.puml @@ -3,6 +3,6 @@ participant "Provider" participant "Consumer" -"Consumer" -> "Provider" : Subscribe - response (id, uri) +"Consumer" -> "Provider" : Subscribe - response (entity id, consumer uri) @enduml diff --git a/docs/design/diagrams/subscribe_sequence.svg b/docs/design/diagrams/subscribe_sequence.svg index 6479b472..1afade1e 100644 --- a/docs/design/diagrams/subscribe_sequence.svg +++ b/docs/design/diagrams/subscribe_sequence.svg @@ -1,15 +1,20 @@ -ProviderProviderConsumerConsumerSubscribe - response (id, uri) \ No newline at end of file +In-Vehicle Digital Twin ServiceIn-Vehicle Digital Twin ServiceConsumerConsumerFindById - request (entity id)FindById - response (entity access info) \ No newline at end of file diff --git a/docs/design/diagrams/ibeji_component.svg b/docs/design/diagrams/ibeji_component.svg index a2ca53ea..10bcf1e8 100644 --- a/docs/design/diagrams/ibeji_component.svg +++ b/docs/design/diagrams/ibeji_component.svg @@ -1,28 +1 @@ -ConsumerIn-Vehicle Digital Twin ServiceProviderDigitalTwinConsumerInterfaceDigitalTwinInterfaceDigitalTwinProviderInterface \ No newline at end of file +ConsumerIn-Vehicle Digital Twin ServiceProviderDigitalTwinConsumerInterfaceDigitalTwinInterfaceDigitalTwinProviderInterface \ No newline at end of file diff --git a/docs/design/diagrams/invoke_sequence.svg b/docs/design/diagrams/invoke_sequence.svg index 095fa5f8..ba1346f9 100644 --- a/docs/design/diagrams/invoke_sequence.svg +++ b/docs/design/diagrams/invoke_sequence.svg @@ -1,21 +1 @@ -ProviderProviderConsumerConsumerInvoke - request (entity id, consumer uri, response id, payload) \ No newline at end of file +ProviderProviderConsumerConsumerInvoke - request (entity id, consumer uri, response id, payload) \ No newline at end of file diff --git a/docs/design/diagrams/publish_sequence.svg b/docs/design/diagrams/publish_sequence.svg index ecc9c5cf..d4a3e5ce 100644 --- a/docs/design/diagrams/publish_sequence.svg +++ b/docs/design/diagrams/publish_sequence.svg @@ -1,21 +1 @@ -ProviderProviderConsumerConsumerPublish - request (entity id, value) \ No newline at end of file +ProviderProviderConsumerConsumerPublish - request (entity id, value) \ No newline at end of file diff --git a/docs/design/diagrams/register_sequence.svg b/docs/design/diagrams/register_sequence.svg index 3dc43bc2..f4aef8b1 100644 --- a/docs/design/diagrams/register_sequence.svg +++ b/docs/design/diagrams/register_sequence.svg @@ -1,21 +1 @@ -ProviderProviderIn-Vehicle Digital Twin ServiceIn-Vehicle Digital Twin ServiceRegister - request (entity access info list) \ No newline at end of file +ProviderProviderIn-Vehicle Digital Twin ServiceIn-Vehicle Digital Twin ServiceRegister - request (entity access info list) \ No newline at end of file diff --git a/docs/design/diagrams/respond_sequence.svg b/docs/design/diagrams/respond_sequence.svg index 7fe8e0ca..1a2ff9fa 100644 --- a/docs/design/diagrams/respond_sequence.svg +++ b/docs/design/diagrams/respond_sequence.svg @@ -1,21 +1 @@ -ProviderProviderConsumerConsumerRespond - request (entity id, response id, payload) \ No newline at end of file +ProviderProviderConsumerConsumerRespond - request (entity id, response id, payload) \ No newline at end of file diff --git a/docs/design/diagrams/subscribe_sequence.svg b/docs/design/diagrams/subscribe_sequence.svg index 1afade1e..e8cf55a5 100644 --- a/docs/design/diagrams/subscribe_sequence.svg +++ b/docs/design/diagrams/subscribe_sequence.svg @@ -1,21 +1 @@ -ProviderProviderConsumerConsumerSubscribe - response (entity id, consumer uri) \ No newline at end of file +ProviderProviderConsumerConsumerSubscribe - response (entity id, consumer uri) \ No newline at end of file From 687bc6e9f5a8f45cf573390aa6089e8742936b9b Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 15 May 2023 16:01:35 -0700 Subject: [PATCH 40/41] Make protocol agnostic --- docs/design/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/README.md b/docs/design/README.md index ccec3fc6..0725b357 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -220,7 +220,7 @@ Register one or more entities access information. #### Request -- entity_access_info_list - A list of entity access infromation. +- entity_access_info_list - A list of entity access information. #### Response From 11d04ea4dcd796390c6eab84abb16c5eef8cb624 Mon Sep 17 00:00:00 2001 From: Ash Beitz <8304894+ashbeitz@users.noreply.github.com> Date: Mon, 15 May 2023 16:05:03 -0700 Subject: [PATCH 41/41] Make protocol agnostic --- docs/design/.accepted_words.txt | 1 + docs/design/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/design/.accepted_words.txt b/docs/design/.accepted_words.txt index d4c6ffb6..5aa74aab 100644 --- a/docs/design/.accepted_words.txt +++ b/docs/design/.accepted_words.txt @@ -10,6 +10,7 @@ findbyid FindById gRPC http +HVAC metadata org RemotelyAccessible diff --git a/docs/design/README.md b/docs/design/README.md index 0725b357..2383cba8 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -23,7 +23,7 @@ Ibeji has three main architectural concepts: The first Ibeji architectural concept that we will introduce is the Digital Twin Consumer. A Digital Twin Consumer is a software entity that utilizes Ibeji to interface with the digital representation of the In-Vehicle hardware components. -Another Ibeji architectural concept is the Digital Twin Provider. A Digital Twin Provider is the access point to some/all of the vehicle's hardware resources. A Digital Twin Provider registers itself with the In-Vehicle Digital Twin Service. Once registered, the In-Vehicle Digital Twin Service can make the resources available to Digital Twin Consumers. Each resource includes meta data so that DIgital Twin Consumers know how to interact with it. The In-Vehicle Digital Twin Service supports multiple simultaneous Digital Twin Providers and internally resolves overlapping resources offered by multiple Digital Twin Providers. These overlaps offer multiple options for interacting with a resource and can improve the resource's availability (by supporting multiple access paths). +Another Ibeji architectural concept is the Digital Twin Provider. A Digital Twin Provider is the access point to some/all of the vehicle's hardware resources. A Digital Twin Provider registers itself with the In-Vehicle Digital Twin Service. Once registered, the In-Vehicle Digital Twin Service can make the resources available to Digital Twin Consumers. Each resource includes meta data so that Digital Twin Consumers know how to interact with it. The In-Vehicle Digital Twin Service supports multiple simultaneous Digital Twin Providers and internally resolves overlapping resources offered by multiple Digital Twin Providers. These overlaps offer multiple options for interacting with a resource and can improve the resource's availability (by supporting multiple access paths). In the middle is the In-Vehicle Digital Twin Service. It exports a query interface that enables Digital Twin Consumers to discover the vehicle's resources and provides the details necessary to use those resources. The In-Vehicle Digital Twin Service has an interface that allows Digital Twin Providers to dynamically register their resources.