diff --git a/sdk/core/src/macros.rs b/sdk/core/src/macros.rs index de37777e24..7c53424b07 100644 --- a/sdk/core/src/macros.rs +++ b/sdk/core/src/macros.rs @@ -28,7 +28,7 @@ macro_rules! setters { (@single $name:ident : $typ:ty => $transform:expr) => { #[allow(clippy::redundant_field_names)] #[allow(clippy::needless_update)] - // TODO: Declare using idiomatic with_$name when https://github.com/Azure/azure-sdk-for-rust/issues/292 is resolved. + #[allow(missing_docs)] pub fn $name>(self, $name: P) -> Self { let $name: $typ = $name.into(); Self { @@ -123,6 +123,7 @@ macro_rules! setters { macro_rules! operation { // Construct the builder. (@builder + $(#[$outer:meta])* // The name of the operation and any generic params along with their constraints $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)* ),* $(+ $lt:lifetime)?>, // The client @@ -139,6 +140,7 @@ macro_rules! operation { ) => { azure_core::__private::paste! { #[derive(Debug, Clone)] + $(#[$outer])* pub struct [<$name Builder>]<$($generic)*> { client: $client, $($required: $rtype,)* @@ -169,8 +171,45 @@ macro_rules! operation { } } }; + // `operation! { #[stream] ListUsers, client: UserClient, ?consistency_level: ConsistencyLevel }` + (#[stream] $(#[$outer:meta])* $name:ident, + client: $client:ty, + $($required:ident: $rtype:ty,)* + $(?$optional:ident: $otype:ty),*) => { + $crate::operation!{ + @builder + $(#[$outer])* + $name<>, + client: $client, + @required + $($required: $rtype,)* + @optional + $($optional: $otype,)* + @nosetter + } + }; + (#[stream] $(#[$outer:meta])* + $name:ident, + client: $client:ty, + $($required:ident: $rtype:ty,)* + $(?$optional:ident: $otype:ty,)* + $(#[skip]$nosetter:ident: $nstype:ty),* + ) => { + $crate::operation!{ + @builder + $(#[$outer])* + $name<>, + client: $client, + @required + $($required: $rtype,)* + @optional + $($optional: $otype,)* + @nosetter + $($nosetter: $nstype),* + } + }; // Construct a builder and the `Future` related code - ($name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)* ),* $(+ $lt:lifetime)?>, + ($(#[$outer:meta])* $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)* ),* $(+ $lt:lifetime)?>, client: $client:ty, @required $($required:ident: $rtype:ty,)* @@ -180,7 +219,9 @@ macro_rules! operation { $($nosetter:ident: $nstype:ty),* ) => { $crate::operation! { - @builder $name<$($generic: $first_constraint $(+ $constraint)*),* $(+ $lt)*>, + @builder + $(#[$outer])* + $name<$($generic: $first_constraint $(+ $constraint)*),* $(+ $lt)*>, client: $client, @required $($required: $rtype,)* @@ -202,11 +243,12 @@ macro_rules! operation { } }; // `operation! { CreateUser, client: UserClient, ?consistency_level: ConsistencyLevel }` - ($name:ident, + ($(#[$outer:meta])* $name:ident, client: $client:ty, $($required:ident: $rtype:ty,)* $(?$optional:ident: $otype:ty),*) => { $crate::operation!{ + $(#[$outer])* $name<>, client: $client, @required @@ -216,47 +258,14 @@ macro_rules! operation { @nosetter } }; - // `operation! { #[stream] ListUsers, client: UserClient, ?consistency_level: ConsistencyLevel }` - (#[stream] $name:ident, - client: $client:ty, - $($required:ident: $rtype:ty,)* - $(?$optional:ident: $otype:ty),*) => { - $crate::operation!{ - @builder - $name<>, - client: $client, - @required - $($required: $rtype,)* - @optional - $($optional: $otype,)* - @nosetter - } - }; - (#[stream] $name:ident, - client: $client:ty, - $($required:ident: $rtype:ty,)* - $(?$optional:ident: $otype:ty,)* - $(#[skip]$nosetter:ident: $nstype:ty),* - ) => { - $crate::operation!{ - @builder - $name<>, - client: $client, - @required - $($required: $rtype,)* - @optional - $($optional: $otype,)* - @nosetter - $($nosetter: $nstype),* - } - }; // `operation! { CreateDocument, client: UserClient, ?consistency_level: ConsistencyLevel, ??other_field: bool }` - ($name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)*),* $(+ $lt:lifetime)?>, + ($(#[$outer:meta])* $name:ident<$($generic:ident: $first_constraint:ident $(+ $constraint:ident)*),* $(+ $lt:lifetime)?>, client: $client:ty, $($required:ident: $rtype:ty,)* $(?$optional:ident: $otype:ty,)* $(#[skip] $nosetter:ident: $nstype:ty),*) => { $crate::operation!{ + $(#[$outer])* $name<$($generic: $first_constraint $(+ $constraint)*),* $(+ $lt)*>, client: $client, @required diff --git a/sdk/iot_hub/Cargo.toml b/sdk/iot_hub/Cargo.toml index 30bba9c206..3c8786dc7b 100644 --- a/sdk/iot_hub/Cargo.toml +++ b/sdk/iot_hub/Cargo.toml @@ -18,6 +18,7 @@ serde_derive = "1.0" sha2 = "0.10" url = "2.2" thiserror = "1.0" +futures = "0.3" [dev-dependencies] env_logger = "0.9" diff --git a/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs b/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs index 8a95fbed3f..40dfa03fa6 100644 --- a/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs +++ b/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs @@ -62,7 +62,7 @@ async fn main() -> Result<(), Box> { service_client .apply_on_edge_device(device_id) .modules_content(modules_content) - .execute() + .into_future() .await?; println!("Successfully applied the configuration"); diff --git a/sdk/iot_hub/examples/configuration.rs b/sdk/iot_hub/examples/configuration.rs index ae05941759..8718c633de 100644 --- a/sdk/iot_hub/examples/configuration.rs +++ b/sdk/iot_hub/examples/configuration.rs @@ -1,4 +1,4 @@ -use azure_iot_hub::service::ServiceClient; +use azure_iot_hub::service::{resources::Configuration, ServiceClient}; use std::error::Error; #[tokio::main] @@ -29,7 +29,7 @@ async fn main() -> Result<(), Box> { "metric1", "SELECT deviceId FROM devices WHERE properties.reported.lastDesiredStatus.code = 200", ) - .execute() + .into_future() .await?; println!( @@ -38,7 +38,11 @@ async fn main() -> Result<(), Box> { ); println!("Getting configuration: {}", configuration_id); - let configuration = service_client.get_configuration(configuration_id).await?; + let configuration = service_client + .get_configuration(configuration_id) + .into_future() + .await?; + let configuration: Configuration = configuration.try_into()?; println!( "Successfully retrieved the new configuration '{:?}'", @@ -65,10 +69,10 @@ async fn main() -> Result<(), Box> { })) .labels(configuration.labels) .metrics(configuration.metrics.queries) - .execute() + .into_future() .await?; - let multiple_configurations = service_client.get_configurations().await?; + let multiple_configurations = service_client.get_configurations().into_future().await?; println!( "Successfully retrieved all configurations '{:?}'", multiple_configurations @@ -86,7 +90,7 @@ async fn main() -> Result<(), Box> { service_client .delete_configuration(&configuration.id, configuration.etag) - .execute() + .into_future() .await?; println!( diff --git a/sdk/iot_hub/examples/device_identity.rs b/sdk/iot_hub/examples/device_identity.rs index d32f2c728f..194eb4b083 100644 --- a/sdk/iot_hub/examples/device_identity.rs +++ b/sdk/iot_hub/examples/device_identity.rs @@ -1,4 +1,5 @@ use azure_iot_hub::service::resources::{AuthenticationMechanism, DesiredCapability, Status}; +use azure_iot_hub::service::responses::DeviceIdentityResponse; use azure_iot_hub::service::ServiceClient; use std::error::Error; @@ -16,8 +17,7 @@ async fn main() -> Result<(), Box> { let service_client = ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; let device = service_client - .create_device_identity() - .execute( + .create_device_identity( &device_id, Status::Enabled, AuthenticationMechanism::new_using_symmetric_key( @@ -25,6 +25,7 @@ async fn main() -> Result<(), Box> { "6YS6w5wqkpdfkEW7iOP1NvituehFlFRfPko2n7KY4Gk", ), ) + .into_future() .await?; println!("Successfully created a new device '{}'", device.device_id); @@ -34,26 +35,31 @@ async fn main() -> Result<(), Box> { device.device_id ); let device = service_client - .update_device_identity(device.etag) - .device_capability(DesiredCapability::IotEdge) - .execute( + .update_device_identity( &device_id, Status::Enabled, AuthenticationMechanism::new_using_symmetric_key( "QhgevIUBSWe37q1MP+M/vtktjOcrE74BVbpcxlLQw58=", "6YS6w5wqkpdfkEW7iOP1NvituehFlFRfPko2n7KY4Gk", ), + device.etag, ) + .device_capability(DesiredCapability::IotEdge) + .into_future() .await?; println!("Getting device identity of '{}'", device.device_id); - let device = service_client.get_device_identity(device.device_id).await?; + let device = service_client + .get_device_identity(device.device_id) + .into_future() + .await?; + let device: DeviceIdentityResponse = device.try_into()?; println!("Identity is: {:?}", device); println!("Deleting device '{}'", device.device_id); service_client .delete_device_identity(device.device_id, device.etag) - .execute() + .into_future() .await?; Ok(()) diff --git a/sdk/iot_hub/examples/directmethod.rs b/sdk/iot_hub/examples/directmethod.rs index 088508f9e0..4f8835a3b9 100644 --- a/sdk/iot_hub/examples/directmethod.rs +++ b/sdk/iot_hub/examples/directmethod.rs @@ -31,12 +31,14 @@ async fn main() -> Result<(), Box> { method_name, device_id, module_id, service_client.iot_hub_name ); - let direct_method = - service_client.create_module_method(device_id, module_id, method_name, 30, 30); + let direct_method = service_client.create_module_method( + device_id, + module_id, + method_name, + serde_json::from_str(&payload)?, + ); - let response = direct_method - .execute(serde_json::from_str(&payload)?) - .await?; + let response = direct_method.into_future().await?; println!( "Received a response from the direct method with status code {} and payload {:?}", diff --git a/sdk/iot_hub/examples/gettwin.rs b/sdk/iot_hub/examples/gettwin.rs index 44b2770bab..59dc56f94c 100644 --- a/sdk/iot_hub/examples/gettwin.rs +++ b/sdk/iot_hub/examples/gettwin.rs @@ -15,7 +15,10 @@ async fn main() -> Result<(), Box> { let http_client = azure_core::new_http_client(); let service_client = ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; - let twin = service_client.get_device_twin(device_id).await?; + let twin = service_client + .get_device_twin(device_id) + .into_future() + .await?; println!("Received device twin: {:?}", twin); diff --git a/sdk/iot_hub/examples/module_identity.rs b/sdk/iot_hub/examples/module_identity.rs index b1983124e8..3f5f3c100d 100644 --- a/sdk/iot_hub/examples/module_identity.rs +++ b/sdk/iot_hub/examples/module_identity.rs @@ -1,4 +1,5 @@ use azure_iot_hub::service::resources::AuthenticationMechanism; +use azure_iot_hub::service::responses::ModuleIdentityResponse; use azure_iot_hub::service::ServiceClient; use std::error::Error; @@ -19,8 +20,7 @@ async fn main() -> Result<(), Box> { let service_client = ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; let module = service_client - .create_module_identity() - .execute( + .create_module_identity( &device_id, &module_id, "IoTEdge", @@ -29,6 +29,7 @@ async fn main() -> Result<(), Box> { "6YS6w5wqkpdfkEW7iOP1NvituehFlFRfPko2n7KY4Gk", ), ) + .into_future() .await?; println!( @@ -41,8 +42,7 @@ async fn main() -> Result<(), Box> { module.device_id, module.module_id ); let module = service_client - .update_module_identity(module.etag) - .execute( + .update_module_identity( &device_id, &module_id, "Docker", @@ -50,7 +50,9 @@ async fn main() -> Result<(), Box> { "QhgevIUBSWe37q1MP+M/vtktjOcrE74BVbpcxlLQw58=", "6YS6w5wqkpdfkEW7iOP1NvituehFlFRfPko2n7KY4Gk", ), + module.etag, ) + .into_future() .await?; println!( @@ -59,7 +61,9 @@ async fn main() -> Result<(), Box> { ); let module = service_client .get_module_identity(module.device_id, module.module_id) + .into_future() .await?; + let module: ModuleIdentityResponse = module.try_into()?; println!("Identity is: {:?}", module); println!( @@ -68,7 +72,7 @@ async fn main() -> Result<(), Box> { ); service_client .delete_module_identity(module.device_id, module.module_id, module.etag) - .execute() + .into_future() .await?; Ok(()) diff --git a/sdk/iot_hub/examples/query_iothub.rs b/sdk/iot_hub/examples/query_iothub.rs index 64bb04f6fd..3cf75b771b 100644 --- a/sdk/iot_hub/examples/query_iothub.rs +++ b/sdk/iot_hub/examples/query_iothub.rs @@ -16,9 +16,9 @@ async fn main() -> Result<(), Box> { ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; let response = service_client - .query() + .query(query) .max_item_count(1) - .execute(query) + .into_future() .await?; println!( @@ -32,10 +32,10 @@ async fn main() -> Result<(), Box> { }; let response = service_client - .query() + .query(query) .max_item_count(1) .continuation(token) - .execute(query) + .into_future() .await?; println!( diff --git a/sdk/iot_hub/examples/updatetwin.rs b/sdk/iot_hub/examples/updatetwin.rs index df28b74ad8..bdf2ebc006 100644 --- a/sdk/iot_hub/examples/updatetwin.rs +++ b/sdk/iot_hub/examples/updatetwin.rs @@ -22,8 +22,8 @@ async fn main() -> Result<(), Box> { ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; let updated_twin = service_client .update_device_twin(device_id) - .properties(serde_json::from_str(&payload)?) - .execute() + .desired_properties(serde_json::from_str(&payload)?) + .into_future() .await?; println!("Received device twin: {:?}", updated_twin); diff --git a/sdk/iot_hub/src/service/mod.rs b/sdk/iot_hub/src/service/mod.rs index e83097c442..37b1fc71f6 100644 --- a/sdk/iot_hub/src/service/mod.rs +++ b/sdk/iot_hub/src/service/mod.rs @@ -6,24 +6,23 @@ use hmac::{Hmac, Mac}; use sha2::Sha256; use std::sync::Arc; -/// The requests module contains any request that the IoT Hub service client can perform. -pub mod requests; -/// The resources module contains various types that some of the requests or responses use. +/// Contains any operation that the IoT Hub service client can perform. +pub mod operations; +/// Contains various types that some of the requests or responses use. pub mod resources; -/// The response module contains responses for the requests that the IoT Hub service client can perform. +/// Contains responses for the requests that the IoT Hub service client can perform. pub mod responses; -use crate::service::requests::{ - get_configuration, get_identity, get_twin, ApplyOnEdgeDeviceBuilder, - CreateOrUpdateConfigurationBuilder, CreateOrUpdateDeviceIdentityBuilder, - CreateOrUpdateModuleIdentityBuilder, DeleteConfigurationBuilder, DeleteIdentityBuilder, +use crate::service::operations::{ + ApplyOnEdgeDeviceBuilder, CreateOrUpdateConfigurationBuilder, + CreateOrUpdateDeviceIdentityBuilder, CreateOrUpdateModuleIdentityBuilder, + DeleteConfigurationBuilder, DeleteIdentityBuilder, GetIdentityBuilder, GetTwinBuilder, InvokeMethodBuilder, QueryBuilder, UpdateOrReplaceTwinBuilder, }; use crate::service::resources::identity::IdentityOperation; -use crate::service::responses::{ - ConfigurationResponse, DeviceIdentityResponse, DeviceTwinResponse, ModuleIdentityResponse, - ModuleTwinResponse, MultipleConfigurationResponse, -}; + +use self::operations::GetConfigurationBuilder; +use self::resources::{AuthenticationMechanism, Status}; /// The API version to use for any requests pub const API_VERSION: &str = "2020-05-31-preview"; @@ -35,6 +34,7 @@ pub const API_VERSION: &str = "2020-05-31-preview"; /// - providing the connection string. /// The IoTHubService then uses the provided information to create a SAS token that it will /// use to communicate with the IoT Hub. +#[derive(Clone, Debug)] pub struct ServiceClient { http_client: Arc, /// The name of the IoT Hub. @@ -255,27 +255,19 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the service client!"); - /// let device_method = iot_hub.create_device_method("some-device", "hello-world", 30, 30); + /// let device_method = iot_hub.create_device_method("some-device", "hello-world", serde_json::json!({})); /// ``` pub fn create_device_method( &self, device_id: S, method_name: T, - response_time_out: u64, - connect_time_out: u64, - ) -> requests::InvokeMethodBuilder + payload: serde_json::Value, + ) -> operations::InvokeMethodBuilder where S: Into, T: Into, { - InvokeMethodBuilder::new( - self, - device_id.into(), - None, - method_name.into(), - connect_time_out, - response_time_out, - ) + InvokeMethodBuilder::new(self.clone(), device_id.into(), method_name.into(), payload) } /// Create a new module method @@ -287,29 +279,22 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let device_method = iot_hub.create_module_method("some-device", "some-module", "hello-world", 30, 30); + /// let device_method = iot_hub.create_module_method("some-device", "some-module", "hello-world", serde_json::json!({})); /// ``` pub fn create_module_method( &self, device_id: S, module_id: T, method_name: U, - response_time_out: u64, - connect_time_out: u64, - ) -> requests::InvokeMethodBuilder + payload: serde_json::Value, + ) -> operations::InvokeMethodBuilder where S: Into, T: Into, U: Into, { - InvokeMethodBuilder::new( - self, - device_id.into(), - Some(module_id.into()), - method_name.into(), - connect_time_out, - response_time_out, - ) + InvokeMethodBuilder::new(self.clone(), device_id.into(), method_name.into(), payload) + .module_id(module_id.into()) } /// Get the module twin of a given device and module @@ -323,21 +308,12 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.get_module_twin("some-device", "some-module"); /// ``` - pub async fn get_module_twin( - &self, - device_id: S, - module_id: T, - ) -> azure_core::Result + pub fn get_module_twin(&self, device_id: S, module_id: T) -> GetTwinBuilder where S: Into, T: Into, { - get_twin(self, device_id.into(), Some(module_id.into())).await - } - - /// Get the HttpClient of the IoTHub service - pub(crate) fn http_client(&self) -> &dyn HttpClient { - self.http_client.as_ref() + GetTwinBuilder::new(self.clone(), device_id.into()).module_id(module_id) } /// Get the device twin of a given device @@ -351,11 +327,11 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.get_device_twin("some-device"); /// ``` - pub async fn get_device_twin(&self, device_id: S) -> azure_core::Result + pub fn get_device_twin(&self, device_id: S) -> GetTwinBuilder where S: Into, { - get_twin(self, device_id.into(), None).await + GetTwinBuilder::new(self.clone(), device_id.into()) } /// Update the module twin of a given device or module @@ -369,24 +345,16 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.update_module_twin("some-device", "some-module") /// .tag("TagName", "TagValue") - /// .properties(serde_json::json!({"PropertyName": "PropertyValue"})) - /// .execute(); + /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) + /// .into_future(); /// ``` - pub fn update_module_twin( - &self, - device_id: S, - module_id: T, - ) -> UpdateOrReplaceTwinBuilder<'_, ModuleTwinResponse> + pub fn update_module_twin(&self, device_id: S, module_id: T) -> UpdateOrReplaceTwinBuilder where S: Into, T: Into, { - UpdateOrReplaceTwinBuilder::new( - self, - device_id.into(), - Some(module_id.into()), - Method::Patch, - ) + UpdateOrReplaceTwinBuilder::new(self.clone(), device_id.into(), Method::Patch) + .module_id(module_id.into()) } /// Replace the module twin of a given device and module @@ -400,19 +368,20 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.replace_module_twin("some-device", "some-module") /// .tag("TagName", "TagValue") - /// .properties(serde_json::json!({"PropertyName": "PropertyValue"})) - /// .execute(); + /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) + /// .into_future(); /// ``` pub fn replace_module_twin( &self, device_id: S, module_id: T, - ) -> UpdateOrReplaceTwinBuilder<'_, ModuleTwinResponse> + ) -> UpdateOrReplaceTwinBuilder where S: Into, T: Into, { - UpdateOrReplaceTwinBuilder::new(self, device_id.into(), Some(module_id.into()), Method::Put) + UpdateOrReplaceTwinBuilder::new(self.clone(), device_id.into(), Method::Put) + .module_id(module_id.into()) } /// Update the device twin of a given device @@ -426,17 +395,14 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.update_device_twin("some-device") /// .tag("TagName", "TagValue") - /// .properties(serde_json::json!({"PropertyName": "PropertyValue"})) - /// .execute(); + /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) + /// .into_future(); /// ``` - pub fn update_device_twin( - &self, - device_id: S, - ) -> UpdateOrReplaceTwinBuilder<'_, DeviceTwinResponse> + pub fn update_device_twin(&self, device_id: S) -> UpdateOrReplaceTwinBuilder where S: Into, { - UpdateOrReplaceTwinBuilder::new(self, device_id.into(), None, Method::Patch) + UpdateOrReplaceTwinBuilder::new(self.clone(), device_id.into(), Method::Patch) } /// Replace the device twin of a given device @@ -450,17 +416,14 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.replace_device_twin("some-device") /// .tag("TagName", "TagValue") - /// .properties(serde_json::json!({"PropertyName": "PropertyValue"})) - /// .execute(); + /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) + /// .into_future(); /// ``` - pub fn replace_device_twin( - &self, - device_id: S, - ) -> UpdateOrReplaceTwinBuilder<'_, DeviceTwinResponse> + pub fn replace_device_twin(&self, device_id: S) -> UpdateOrReplaceTwinBuilder where S: Into, { - UpdateOrReplaceTwinBuilder::new(self, device_id.into(), None, Method::Put) + UpdateOrReplaceTwinBuilder::new(self.clone(), device_id.into(), Method::Put) } /// Get the identity of a given device @@ -474,14 +437,11 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_device_identity("some-device"); /// ``` - pub async fn get_device_identity( - &self, - device_id: S, - ) -> azure_core::Result + pub fn get_device_identity(&self, device_id: S) -> GetIdentityBuilder where S: Into, { - get_identity(self, device_id.into(), None).await + GetIdentityBuilder::new(self.clone(), device_id.into()) } /// Create a new device identity @@ -494,11 +454,26 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let device = iot_hub.create_device_identity() - /// .execute("some-existing-device", Status::Enabled, AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")); + /// let device = iot_hub.create_device_identity("some-existing-device", Status::Enabled, AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")) + /// .into_future(); /// ``` - pub fn create_device_identity(&self) -> CreateOrUpdateDeviceIdentityBuilder { - CreateOrUpdateDeviceIdentityBuilder::new(self, IdentityOperation::Create, None) + pub fn create_device_identity( + &self, + device_id: S, + status: Status, + authentication: AuthenticationMechanism, + ) -> CreateOrUpdateDeviceIdentityBuilder + where + S: Into, + { + CreateOrUpdateDeviceIdentityBuilder::new( + self.clone(), + IdentityOperation::Create, + device_id.into(), + status, + authentication, + None, + ) } /// Update an existing device identity @@ -511,14 +486,27 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let device = iot_hub.update_device_identity("etag-of-device-to-update") - /// .execute("some-existing-device", Status::Enabled, AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")); + /// let device = iot_hub.update_device_identity("some-existing-device", Status::Enabled, AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key"), "etag-of-device-to-update"); /// ``` - pub fn update_device_identity(&self, etag: S) -> CreateOrUpdateDeviceIdentityBuilder + pub fn update_device_identity( + &self, + device_id: S1, + status: Status, + authentication: AuthenticationMechanism, + etag: S2, + ) -> CreateOrUpdateDeviceIdentityBuilder where - S: Into, + S1: Into, + S2: Into, { - CreateOrUpdateDeviceIdentityBuilder::new(self, IdentityOperation::Update, Some(etag.into())) + CreateOrUpdateDeviceIdentityBuilder::new( + self.clone(), + IdentityOperation::Update, + device_id.into(), + status, + authentication, + Some(etag.into()), + ) } /// Delete a device identity @@ -535,16 +523,12 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.delete_device_identity("some-device-id", "some-etag"); /// ``` - pub fn delete_device_identity( - &self, - device_id: S, - if_match: T, - ) -> DeleteIdentityBuilder<'_> + pub fn delete_device_identity(&self, device_id: S, if_match: T) -> DeleteIdentityBuilder where S: Into, T: Into, { - DeleteIdentityBuilder::new(self, if_match.into(), device_id.into(), None) + DeleteIdentityBuilder::new(self.clone(), if_match.into(), device_id.into(), None) } /// Get the identity of a given module @@ -558,16 +542,12 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_module_identity("some-device", "some-module"); /// ``` - pub async fn get_module_identity( - &self, - device_id: S, - module_id: T, - ) -> azure_core::Result + pub fn get_module_identity(&self, device_id: S, module_id: T) -> GetIdentityBuilder where S: Into, T: Into, { - get_identity(self, device_id.into(), Some(module_id.into())).await + GetIdentityBuilder::new(self.clone(), device_id.into()).module_id(module_id) } /// Create a new module identity @@ -580,11 +560,29 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let device = iot_hub.create_module_identity() - /// .execute("some-existing-device", "some-existing-module", "IoTEdge", AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")); + /// let device = iot_hub.create_module_identity("some-existing-device", "some-existing-module", "IoTEdge", AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")).into_future(); /// ``` - pub fn create_module_identity(&self) -> CreateOrUpdateModuleIdentityBuilder { - CreateOrUpdateModuleIdentityBuilder::new(self, IdentityOperation::Create, None) + pub fn create_module_identity( + &self, + device_id: S1, + module_id: S2, + managed_by: S3, + authentication: AuthenticationMechanism, + ) -> CreateOrUpdateModuleIdentityBuilder + where + S1: Into, + S2: Into, + S3: Into, + { + CreateOrUpdateModuleIdentityBuilder::new( + self.clone(), + IdentityOperation::Create, + device_id.into(), + module_id.into(), + managed_by.into(), + authentication, + None, + ) } /// Update an existing module identity @@ -597,14 +595,31 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let device = iot_hub.update_module_identity("etag-of-device-to-update") - /// .execute("some-existing-device", "some-existing-module", "IoTEdge", AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")); + /// let device = iot_hub.update_module_identity("some-existing-device", "some-existing-module", "IoTEdge", AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key"), "etag-of-device-to-update"); /// ``` - pub fn update_module_identity(&self, etag: S) -> CreateOrUpdateModuleIdentityBuilder + pub fn update_module_identity( + &self, + device_id: S1, + module_id: S2, + managed_by: S3, + authentication: AuthenticationMechanism, + etag: S4, + ) -> CreateOrUpdateModuleIdentityBuilder where - S: Into, + S1: Into, + S2: Into, + S3: Into, + S4: Into, { - CreateOrUpdateModuleIdentityBuilder::new(self, IdentityOperation::Update, Some(etag.into())) + CreateOrUpdateModuleIdentityBuilder::new( + self.clone(), + IdentityOperation::Update, + device_id.into(), + module_id.into(), + managed_by.into(), + authentication, + Some(etag.into()), + ) } /// Create a new device identity @@ -626,14 +641,14 @@ impl ServiceClient { device_id: S, module_id: T, if_match: U, - ) -> DeleteIdentityBuilder<'_> + ) -> DeleteIdentityBuilder where S: Into, T: Into, U: Into, { DeleteIdentityBuilder::new( - self, + self.clone(), if_match.into(), device_id.into(), Some(module_id.into()), @@ -649,10 +664,13 @@ impl ServiceClient { /// # let http_client = azure_core::new_http_client(); /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let query_builder = iot_hub.query(); + /// let query_builder = iot_hub.query("$SOME_QUERY"); /// ``` - pub fn query(&self) -> QueryBuilder<'_> { - QueryBuilder::new(self) + pub fn query(&self, query: Q) -> QueryBuilder + where + Q: Into, + { + QueryBuilder::new(self.clone(), query.into()) } /// Apply configuration on an Edge device @@ -670,7 +688,7 @@ impl ServiceClient { where S: Into, { - ApplyOnEdgeDeviceBuilder::new(self, device_id.into()) + ApplyOnEdgeDeviceBuilder::new(self.clone(), device_id.into()) } /// Get a configuration @@ -684,14 +702,11 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_configuration("some-configuration"); /// ``` - pub async fn get_configuration( - &self, - configuration_id: S, - ) -> azure_core::Result + pub fn get_configuration(&self, configuration_id: S) -> GetConfigurationBuilder where S: Into, { - get_configuration(self, Some(configuration_id.into())).await + GetConfigurationBuilder::new(self.clone()).configuration_id(configuration_id.into()) } /// Get all configurations @@ -705,8 +720,8 @@ impl ServiceClient { /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_configurations(); /// ``` - pub async fn get_configurations(&self) -> azure_core::Result { - get_configuration(self, None).await + pub fn get_configurations(&self) -> GetConfigurationBuilder { + GetConfigurationBuilder::new(self.clone()) } /// Create a new configuration. @@ -720,7 +735,7 @@ impl ServiceClient { /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let configuration = iot_hub.create_configuration("some-configuration-id", 10, "tags.environment='test'") - /// .execute(); + /// .into_future(); /// ``` pub fn create_configuration( &self, @@ -733,7 +748,7 @@ impl ServiceClient { T: Into, { CreateOrUpdateConfigurationBuilder::new( - self, + self.clone(), configuration_id.into(), priority, target_condition.into(), @@ -752,7 +767,7 @@ impl ServiceClient { /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let configuration = iot_hub.update_configuration("some-configuration-id", 10, "tags.environment='test'", "some-etag-value") - /// .execute(); + /// .into_future(); /// ``` pub fn update_configuration( &self, @@ -767,7 +782,7 @@ impl ServiceClient { U: Into, { CreateOrUpdateConfigurationBuilder::new( - self, + self.clone(), configuration_id.into(), priority, target_condition.into(), @@ -793,12 +808,12 @@ impl ServiceClient { &self, configuration_id: S, if_match: T, - ) -> DeleteConfigurationBuilder<'_> + ) -> DeleteConfigurationBuilder where S: Into, T: Into, { - DeleteConfigurationBuilder::new(self, if_match.into(), configuration_id.into()) + DeleteConfigurationBuilder::new(self.clone(), if_match.into(), configuration_id.into()) } /// Prepares a request that can be used by any request builders. @@ -812,6 +827,11 @@ impl ServiceClient { request.insert_headers(&ContentType::APPLICATION_JSON); Ok(request) } + + /// Get the HttpClient of the IoTHub service + pub(crate) fn http_client(&self) -> &dyn HttpClient { + self.http_client.as_ref() + } } #[cfg(test)] @@ -862,72 +882,4 @@ mod tests { let _ = ServiceClient::from_connection_string(http_client, "HostName=cool-iot-hub.azure-devices.net;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg==", 3600).is_err(); Ok(()) } - - #[test] - fn update_module_twin_should_create_builder() -> Result<(), Box> { - use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - - let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - let service_client = - ServiceClient::from_connection_string(http_client, connection_string, 3600)?; - - let builder = service_client.update_module_twin("deviceid", "moduleid"); - assert_eq!(builder.device_id, "deviceid".to_string()); - assert_eq!(builder.module_id, Some("moduleid".to_string())); - assert_eq!(builder.method, azure_core::Method::Patch); - - Ok(()) - } - - #[test] - fn replace_module_twin_should_create_builder() -> Result<(), Box> { - use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - - let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - let service_client = - ServiceClient::from_connection_string(http_client, connection_string, 3600)?; - - let builder = service_client.replace_module_twin("deviceid", "moduleid"); - assert_eq!(builder.device_id, "deviceid".to_string()); - assert_eq!(builder.module_id, Some("moduleid".to_string())); - assert_eq!(builder.method, azure_core::Method::Put); - - Ok(()) - } - - #[test] - fn update_device_twin_should_create_builder() -> Result<(), Box> { - use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - - let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - let service_client = - ServiceClient::from_connection_string(http_client, connection_string, 3600)?; - - let builder = service_client.update_device_twin("deviceid"); - assert_eq!(builder.device_id, "deviceid".to_string()); - assert_eq!(builder.module_id, None); - assert_eq!(builder.method, azure_core::Method::Patch); - - Ok(()) - } - - #[test] - fn replace_device_twin_should_create_builder() -> Result<(), Box> { - use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - - let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - let service_client = - ServiceClient::from_connection_string(http_client, connection_string, 3600)?; - - let builder = service_client.replace_device_twin("deviceid"); - assert_eq!(builder.device_id, "deviceid".to_string()); - assert_eq!(builder.module_id, None); - assert_eq!(builder.method, azure_core::Method::Put); - - Ok(()) - } } diff --git a/sdk/iot_hub/src/service/operations/apply_on_edge_device.rs b/sdk/iot_hub/src/service/operations/apply_on_edge_device.rs new file mode 100644 index 0000000000..2ca449ff45 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/apply_on_edge_device.rs @@ -0,0 +1,52 @@ +use crate::service::{ServiceClient, API_VERSION}; + +use azure_core::{operation, Method}; +use serde::Serialize; +operation! { + /// The ApplyOnEdgeDeviceBuilder is used to construct a new device identity + /// or the update an existing one. + ApplyOnEdgeDevice, + client: ServiceClient, + device_id: String, + ?device_content: serde_json::Value, + ?module_content: serde_json::Value, + ?modules_content: serde_json::Value +} + +impl ApplyOnEdgeDeviceBuilder { + /// Performs the apply on edge device request + pub fn into_future(self) -> ApplyOnEdgeDevice { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/devices/{}/applyConfigurationContent?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ); + + let mut request = self.client.finalize_request(&uri, Method::Post)?; + let body = ApplyOnEdgeDeviceBody { + device_content: self.device_content.unwrap_or_default(), + module_content: self.module_content.unwrap_or_default(), + modules_content: self.modules_content.unwrap_or_default(), + }; + + let body = azure_core::to_json(&body)?; + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await?; + Ok(()) + }) + } +} + +pub type ApplyOnEdgeDeviceResponse = (); + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct ApplyOnEdgeDeviceBody { + device_content: serde_json::Value, + module_content: serde_json::Value, + modules_content: serde_json::Value, +} diff --git a/sdk/iot_hub/src/service/operations/create_or_update_configuration.rs b/sdk/iot_hub/src/service/operations/create_or_update_configuration.rs new file mode 100644 index 0000000000..0a039f584d --- /dev/null +++ b/sdk/iot_hub/src/service/operations/create_or_update_configuration.rs @@ -0,0 +1,127 @@ +use azure_core::headers; +use azure_core::Method; +use serde::Serialize; +use std::collections::HashMap; +use std::convert::TryInto; + +use crate::service::resources::{ConfigurationContent, ConfigurationMetrics}; +use crate::service::responses::ConfigurationResponse; +use crate::service::{ServiceClient, API_VERSION}; + +azure_core::operation! { + /// The CreateOrUpdateConfigurationBuilder is used to construct a new configuration + /// or update an existing one. + CreateOrUpdateConfiguration, + client: ServiceClient, + configuration_id: String, + priority: u64, + target_condition: String, + etag: Option, + ?content: ConfigurationContent, + ?metrics: HashMap, + ?labels: HashMap +} + +impl CreateOrUpdateConfigurationBuilder { + /// Sets the device content for the configuration + /// The content cannot be updated once it has been created. + pub fn device_content(mut self, device_content: serde_json::Value) -> Self { + let content = self.content.get_or_insert(Default::default()); + content.device_content = Some(device_content); + self + } + + /// Sets the module content for the configuration. + /// The content cannot be updated once it has been created. + pub fn module_content(mut self, module_content: serde_json::Value) -> Self { + let content = self.content.get_or_insert(Default::default()); + content.module_content = Some(module_content); + self + } + + /// Sets the module content for the configuration + /// The content cannot be updated once it has been created. + pub fn modules_content(mut self, modules_content: serde_json::Value) -> Self { + let content = self.content.get_or_insert(Default::default()); + content.modules_content = Some(modules_content); + self + } + + /// Add a metric to the configuration + pub fn metric(mut self, key: S, value: T) -> Self + where + S: Into, + T: Into, + { + let metrics = self.metrics.get_or_insert(Default::default()); + metrics.insert(key.into(), value.into()); + self + } + + /// Add a label to the configuration. + pub fn label(mut self, key: S, value: T) -> Self + where + S: Into, + T: Into, + { + let labels = self.labels.get_or_insert(Default::default()); + labels.insert(key.into(), value.into()); + self + } + + /// Performs the create or update request on the device identity + pub fn into_future(self) -> CreateOrUpdateConfiguration { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/configurations/{}?api-version={}", + self.client.iot_hub_name, &self.configuration_id, API_VERSION + ); + + let mut request = self.client.finalize_request(&uri, Method::Put)?; + + match &self.etag { + Some(etag) => { + request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); + } + None => (), + } + + let body = CreateOrUpdateConfigurationBody { + content: self.content.unwrap_or_default(), + etag: self.etag, + id: &self.configuration_id, + labels: self.labels.unwrap_or_default(), + metrics: ConfigurationMetrics { + queries: self.metrics.unwrap_or_default(), + results: HashMap::new(), + }, + priority: self.priority, + target_condition: &self.target_condition, + }; + + let body = azure_core::to_json(&body)?; + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await? + .try_into() + }) + } +} + +pub type CreateOrUpdateConfigurationResponse = ConfigurationResponse; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct CreateOrUpdateConfigurationBody<'a, 'b> { + content: ConfigurationContent, + #[serde(skip_serializing_if = "Option::is_none")] + etag: Option, + id: &'a str, + labels: HashMap, + metrics: ConfigurationMetrics, + priority: u64, + target_condition: &'b str, +} diff --git a/sdk/iot_hub/src/service/operations/create_or_update_device_identity.rs b/sdk/iot_hub/src/service/operations/create_or_update_device_identity.rs new file mode 100644 index 0000000000..e295b03f3c --- /dev/null +++ b/sdk/iot_hub/src/service/operations/create_or_update_device_identity.rs @@ -0,0 +1,90 @@ +use crate::service::resources::{ + identity::DesiredCapability, identity::IdentityOperation, AuthenticationMechanism, + DeviceCapabilities, Status, +}; +use crate::service::responses::DeviceIdentityResponse; +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::error::{Error, ErrorKind}; +use azure_core::headers; +use azure_core::Method; +use serde::Serialize; +use std::convert::TryInto; + +azure_core::operation! { + /// The CreateOrUpdateDeviceIdentityBuilder is used to construct a new device identity + /// or the update an existing one. + CreateOrUpdateDeviceIdentity, + client: ServiceClient, + operation: IdentityOperation, + device_id: String, + status: Status, + authentication: AuthenticationMechanism, + etag: Option, + ?capabilities: DeviceCapabilities +} + +impl CreateOrUpdateDeviceIdentityBuilder { + /// Sets a device capability on the device + pub fn device_capability(mut self, desired_capability: DesiredCapability) -> Self { + match desired_capability { + DesiredCapability::IotEdge => { + let caps = self + .capabilities + .get_or_insert(DeviceCapabilities::default()); + caps.iotedge = true; + } + } + self + } + + /// Performs the create or update request on the device identity + pub fn into_future(self) -> CreateOrUpdateDeviceIdentity { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/devices/{}?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ); + + let mut request = self.client.finalize_request(&uri, Method::Put)?; + + if self.operation == IdentityOperation::Update { + match &self.etag { + Some(etag) => { + request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); + } + None => return Err(Error::message(ErrorKind::Other, "etag is not set")), + } + } + + let body = CreateOrUpdateDeviceIdentityBody { + authentication: self.authentication, + device_id: &self.device_id, + status: self.status, + capabilities: self.capabilities.unwrap_or_default(), + etag: self.etag, + }; + + let body = azure_core::to_json(&body)?; + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await? + .try_into() + }) + } +} + +pub type CreateOrUpdateDeviceIdentityResponse = DeviceIdentityResponse; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct CreateOrUpdateDeviceIdentityBody<'a> { + authentication: AuthenticationMechanism, + device_id: &'a str, + status: Status, + capabilities: DeviceCapabilities, + #[serde(skip_serializing_if = "Option::is_none")] + etag: Option, +} diff --git a/sdk/iot_hub/src/service/operations/create_or_update_module_identity.rs b/sdk/iot_hub/src/service/operations/create_or_update_module_identity.rs new file mode 100644 index 0000000000..3d98496426 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/create_or_update_module_identity.rs @@ -0,0 +1,74 @@ +use crate::service::resources::{identity::IdentityOperation, AuthenticationMechanism}; +use crate::service::responses::ModuleIdentityResponse; +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::error::{Error, ErrorKind}; +use azure_core::headers; +use azure_core::Method; +use serde::Serialize; +use std::convert::TryInto; + +azure_core::operation! { + /// The CreateOrUpdateModuleIdentityBuilder is used to construct a new module identity + /// or the update an existing one. + CreateOrUpdateModuleIdentity, + client: ServiceClient, + operation: IdentityOperation, + device_id: String, + module_id: String, + managed_by: String, + authentication: AuthenticationMechanism, + etag: Option, +} + +impl CreateOrUpdateModuleIdentityBuilder { + /// Performs the create or update request on the device identity + pub fn into_future(self) -> CreateOrUpdateModuleIdentity { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", + self.client.iot_hub_name, self.device_id, self.module_id, API_VERSION + ); + + let mut request = self.client.finalize_request(&uri, Method::Put)?; + + if self.operation == IdentityOperation::Update { + match &self.etag { + Some(etag) => { + request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); + } + None => return Err(Error::message(ErrorKind::Other, "etag is not set")), + } + } + + let body = CreateOrUpdateModuleIdentityBody { + authentication: self.authentication, + device_id: self.device_id.as_ref(), + module_id: self.module_id.as_ref(), + managed_by: self.managed_by.as_ref(), + etag: self.etag, + }; + + let body = azure_core::to_json(&body)?; + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await? + .try_into() + }) + } +} + +pub type CreateOrUpdateModuleIdentityResponse = ModuleIdentityResponse; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct CreateOrUpdateModuleIdentityBody<'a, 'b, 'c> { + authentication: AuthenticationMechanism, + device_id: &'a str, + module_id: &'b str, + managed_by: &'c str, + #[serde(skip_serializing_if = "Option::is_none")] + etag: Option, +} diff --git a/sdk/iot_hub/src/service/operations/delete_configuration.rs b/sdk/iot_hub/src/service/operations/delete_configuration.rs new file mode 100644 index 0000000000..cb63d374a7 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/delete_configuration.rs @@ -0,0 +1,37 @@ +use crate::service::{ServiceClient, API_VERSION}; + +use azure_core::headers; +use azure_core::Method; + +azure_core::operation! { + /// The DeleteConfigurationBuilder is used to construct a request to delete a configuration. + DeleteConfiguration, + client: ServiceClient, + if_match: String, + configuration_id: String, +} + +impl DeleteConfigurationBuilder { + /// Execute the request to delete the configuration. + pub fn into_future(self) -> DeleteConfiguration { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/configurations/{}?api-version={}", + self.client.iot_hub_name, self.configuration_id, API_VERSION + ); + + let mut request = self.client.finalize_request(&uri, Method::Delete)?; + request.insert_header(headers::IF_MATCH, format!("\"{}\"", &self.if_match)); + + request.set_body(azure_core::EMPTY_BODY); + + self.client + .http_client() + .execute_request_check_status(&request) + .await?; + Ok(()) + }) + } +} + +pub type DeleteConfigurationResponse = (); diff --git a/sdk/iot_hub/src/service/operations/delete_identity.rs b/sdk/iot_hub/src/service/operations/delete_identity.rs new file mode 100644 index 0000000000..207e35c213 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/delete_identity.rs @@ -0,0 +1,43 @@ +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::headers; +use azure_core::Method; + +azure_core::operation! { + /// The DeleteIdentityBuilder is used to construct a request to delete a module or device identity. + DeleteIdentity, + client: ServiceClient, + if_match: String, + device_id: String, + module_id: Option, +} + +impl DeleteIdentityBuilder { + /// Execute the request to delete the module or device identity. + pub fn into_future(self) -> DeleteIdentity { + Box::pin(async move { + let uri = match &self.module_id { + Some(module_id) => format!( + "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", + self.client.iot_hub_name, self.device_id, module_id, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/devices/{}?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, Method::Delete)?; + request.insert_header(headers::IF_MATCH, format!("\"{}\"", &self.if_match)); + + request.set_body(azure_core::EMPTY_BODY); + + self.client + .http_client() + .execute_request_check_status(&request) + .await?; + Ok(()) + }) + } +} + +pub type DeleteIdentityResponse = (); diff --git a/sdk/iot_hub/src/service/operations/get_configuration.rs b/sdk/iot_hub/src/service/operations/get_configuration.rs new file mode 100644 index 0000000000..139e57d53f --- /dev/null +++ b/sdk/iot_hub/src/service/operations/get_configuration.rs @@ -0,0 +1,38 @@ +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::Method; + +azure_core::operation! { + /// The GetConfigurationBuilder is used to get configuration + GetConfiguration, + client: ServiceClient, + ?configuration_id: String + +} + +impl GetConfigurationBuilder { + /// Execute the request to get the configuration of a given identifier. + pub fn into_future(self) -> GetConfiguration { + Box::pin(async move { + let uri = match self.configuration_id { + Some(val) => format!( + "https://{}.azure-devices.net/configurations/{}?api-version={}", + self.client.iot_hub_name, val, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/configurations?api-version={}", + self.client.iot_hub_name, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, Method::Get)?; + request.set_body(azure_core::EMPTY_BODY); + + self.client + .http_client() + .execute_request_check_status(&request) + .await + }) + } +} + +pub type GetConfigurationResponse = crate::service::CollectedResponse; diff --git a/sdk/iot_hub/src/service/operations/get_identity.rs b/sdk/iot_hub/src/service/operations/get_identity.rs new file mode 100644 index 0000000000..8ab6d1207e --- /dev/null +++ b/sdk/iot_hub/src/service/operations/get_identity.rs @@ -0,0 +1,38 @@ +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::Method; + +azure_core::operation! { + /// The GetIdentityBuilder is used to construct a request to get identity + GetIdentity, + client: ServiceClient, + device_id: String, + ?module_id: String +} + +impl GetIdentityBuilder { + /// Execute the request to get the identity of a device or module. + pub fn into_future(self) -> GetIdentity { + Box::pin(async move { + let uri = match self.module_id { + Some(module_id) => format!( + "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", + self.client.iot_hub_name, self.device_id, module_id, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/devices/{}?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, Method::Get)?; + request.set_body(azure_core::EMPTY_BODY); + + self.client + .http_client() + .execute_request_check_status(&request) + .await + }) + } +} + +pub type GetIdentityResponse = crate::service::CollectedResponse; diff --git a/sdk/iot_hub/src/service/operations/get_twin.rs b/sdk/iot_hub/src/service/operations/get_twin.rs new file mode 100644 index 0000000000..8389ebb058 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/get_twin.rs @@ -0,0 +1,38 @@ +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::Method; + +azure_core::operation! { + /// The GetTwinBuilder is used to construct a request to get a twin module or device + GetTwin, + client: ServiceClient, + device_id: String, + ?module_id: String +} + +impl GetTwinBuilder { + /// Execute the request to get the twin of a module or device. + pub fn into_future(self) -> GetTwin { + Box::pin(async move { + let uri = match self.module_id { + Some(val) => format!( + "https://{}.azure-devices.net/twins/{}/modules/{}?api-version={}", + self.client.iot_hub_name, self.device_id, val, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/twins/{}?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, Method::Get)?; + request.set_body(azure_core::EMPTY_BODY); + + self.client + .http_client() + .execute_request_check_status(&request) + .await + }) + } +} + +pub type GetTwinResponse = crate::service::CollectedResponse; diff --git a/sdk/iot_hub/src/service/operations/invoke_method.rs b/sdk/iot_hub/src/service/operations/invoke_method.rs new file mode 100644 index 0000000000..868e6a6aa3 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/invoke_method.rs @@ -0,0 +1,64 @@ +use crate::service::responses::InvokeMethodResponse; +use crate::service::{ServiceClient, API_VERSION}; +use azure_core::Method; +use serde::Serialize; +use std::convert::TryInto; + +azure_core::operation! { + /// The InvokeMethodBuilder is used for constructing the request to + /// invoke a module or device method. + InvokeMethod, + client: ServiceClient, + device_id: String, + method_name: String, + payload: serde_json::Value, + ?module_id: String, + ?response_time_out: u64, + ?connect_time_out: u64 +} + +impl InvokeMethodBuilder { + /// Turn the builder into a `Future` + pub fn into_future(self) -> InvokeMethod { + Box::pin(async move { + let uri = match &self.module_id { + Some(module_id_value) => format!( + "https://{}.azure-devices.net/twins/{}/modules/{}/methods?api-version={}", + self.client.iot_hub_name, self.device_id, module_id_value, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/twins/{}/methods?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, Method::Post)?; + let method = InvokeMethodBody { + connect_timeout_in_seconds: self.connect_time_out.unwrap_or(15), + method_name: &self.method_name, + payload: self.payload, + response_timeout_in_seconds: self.response_time_out.unwrap_or(15), + }; + + let body = azure_core::to_json(&method)?; + + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await? + .try_into() + }) + } +} + +/// Body for the InvokeMethod request +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +struct InvokeMethodBody<'a> { + connect_timeout_in_seconds: u64, + method_name: &'a str, + payload: serde_json::Value, + response_timeout_in_seconds: u64, +} diff --git a/sdk/iot_hub/src/service/operations/mod.rs b/sdk/iot_hub/src/service/operations/mod.rs new file mode 100644 index 0000000000..195f8c4860 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/mod.rs @@ -0,0 +1,25 @@ +mod apply_on_edge_device; +mod create_or_update_configuration; +mod create_or_update_device_identity; +mod create_or_update_module_identity; +mod delete_configuration; +mod delete_identity; +mod get_configuration; +mod get_identity; +mod get_twin; +mod invoke_method; +mod query; +mod update_or_replace_twin; + +pub use apply_on_edge_device::ApplyOnEdgeDeviceBuilder; +pub use create_or_update_configuration::CreateOrUpdateConfigurationBuilder; +pub use create_or_update_device_identity::CreateOrUpdateDeviceIdentityBuilder; +pub use create_or_update_module_identity::CreateOrUpdateModuleIdentityBuilder; +pub use delete_configuration::DeleteConfigurationBuilder; +pub use delete_identity::DeleteIdentityBuilder; +pub use get_configuration::GetConfigurationBuilder; +pub use get_identity::GetIdentityBuilder; +pub use get_twin::GetTwinBuilder; +pub use invoke_method::InvokeMethodBuilder; +pub use query::QueryBuilder; +pub use update_or_replace_twin::UpdateOrReplaceTwinBuilder; diff --git a/sdk/iot_hub/src/service/operations/query.rs b/sdk/iot_hub/src/service/operations/query.rs new file mode 100644 index 0000000000..d83478d8e0 --- /dev/null +++ b/sdk/iot_hub/src/service/operations/query.rs @@ -0,0 +1,48 @@ +#![allow(missing_docs)] + +use crate::service::{responses::QueryResponse, ServiceClient, API_VERSION}; +use azure_core::prelude::*; +use azure_core::Method; +use serde::Serialize; +use std::convert::TryInto; + +/// Body for the Query request +#[derive(Serialize, Debug)] +struct QueryBody { + query: String, +} + +azure_core::operation! { + /// Builder for creating queries + Query, + client: ServiceClient, + query: String, + ?max_item_count: MaxItemCount, + ?continuation: Continuation +} + +impl QueryBuilder { + /// Invoke a qiven query on the IoT Hub + pub fn into_future(self) -> Query { + Box::pin(async move { + let uri = format!( + "https://{}.azure-devices.net/devices/query?api-version={}", + self.client.iot_hub_name, API_VERSION + ); + + let query_body = QueryBody { query: self.query }; + let body = azure_core::to_json(&query_body)?; + + let mut request = self.client.finalize_request(&uri, Method::Post)?; + request.add_optional_header(&self.continuation); + request.add_mandatory_header(&self.max_item_count.unwrap_or_default()); + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await? + .try_into() + }) + } +} diff --git a/sdk/iot_hub/src/service/operations/update_or_replace_twin.rs b/sdk/iot_hub/src/service/operations/update_or_replace_twin.rs new file mode 100644 index 0000000000..f5538875fe --- /dev/null +++ b/sdk/iot_hub/src/service/operations/update_or_replace_twin.rs @@ -0,0 +1,108 @@ +use azure_core::headers; +use azure_core::Method; +use serde::Serialize; +use std::collections::HashMap; + +use crate::service::{ServiceClient, API_VERSION}; + +azure_core::operation! { + /// The UpdateOrReplaceTwinBuilder is used to construct a request for + /// updating or replacing a device or module twin. + UpdateOrReplaceTwin, + client: ServiceClient, + device_id: String, + method: Method, + ?module_id: String, + ?if_match: String, + ?desired_properties: serde_json::Value, + ?desired_tags: HashMap +} + +impl UpdateOrReplaceTwinBuilder { + /// Add a new tag to the desired twin. + /// + /// This function can be invoked multiple times to add multiple tags to the desired twin. + /// When adding a tag which is already in the desired twin, its value will be updated. + /// + /// # Example + /// ``` + /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; + /// use azure_iot_hub::service::ServiceClient; + /// # let http_client = azure_core::new_http_client(); + /// + /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); + /// let twin = iot_hub.update_device_twin("some-device") + /// .tag("TagName", "TagValue") + /// .tag("AnotherTag", "WithAnotherValue") + /// .tag("LastTag", "LastValue"); + /// ``` + pub fn tag(mut self, tag_name: T, tag_value: T) -> Self + where + T: Into, + { + let tags = self.desired_tags.get_or_insert(Default::default()); + tags.insert(tag_name.into(), tag_value.into()); + self + } + + /// Updates the twin with the desired settings + /// + /// ``` + /// use azure_iot_hub::service::ServiceClient; + /// + /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; + /// # let http_client = azure_core::new_http_client(); + /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); + /// let twin = iot_hub.update_device_twin("some-device") + /// .tag("TagName", "TagValue") + /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) + /// .into_future(); + /// ``` + pub fn into_future(self) -> UpdateOrReplaceTwin { + Box::pin(async move { + let body = DesiredTwinBody { + tags: self.desired_tags.unwrap_or_default(), + properties: DesiredTwinProperties { + desired: self.desired_properties.unwrap_or_default(), + }, + }; + + let uri = match self.module_id { + Some(val) => format!( + "https://{}.azure-devices.net/twins/{}/modules/{}?api-version={}", + self.client.iot_hub_name, self.device_id, val, API_VERSION + ), + None => format!( + "https://{}.azure-devices.net/twins/{}?api-version={}", + self.client.iot_hub_name, self.device_id, API_VERSION + ), + }; + + let mut request = self.client.finalize_request(&uri, self.method)?; + if let Some(if_match) = self.if_match { + request.insert_header(headers::IF_MATCH, format!("\"{}\"", if_match)); + } + let body = azure_core::to_json(&body)?; + + request.set_body(body); + + self.client + .http_client() + .execute_request_check_status(&request) + .await + }) + } +} + +pub type UpdateOrReplaceTwinResponse = crate::service::CollectedResponse; + +#[derive(Serialize)] +struct DesiredTwinProperties { + desired: serde_json::Value, +} + +#[derive(Serialize)] +struct DesiredTwinBody { + tags: HashMap, + properties: DesiredTwinProperties, +} diff --git a/sdk/iot_hub/src/service/requests/apply_on_edge_device_builder.rs b/sdk/iot_hub/src/service/requests/apply_on_edge_device_builder.rs deleted file mode 100644 index 1f856ab2f5..0000000000 --- a/sdk/iot_hub/src/service/requests/apply_on_edge_device_builder.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; - -use azure_core::Method; -use serde::Serialize; -/// The ApplyOnEdgeDeviceBuilder is used to construct a new device identity -/// or the update an existing one. -pub struct ApplyOnEdgeDeviceBuilder<'a> { - service_client: &'a ServiceClient, - device_id: String, - device_content: serde_json::Value, - module_content: serde_json::Value, - modules_content: serde_json::Value, -} - -impl<'a> ApplyOnEdgeDeviceBuilder<'a> { - pub(crate) fn new(service_client: &'a ServiceClient, device_id: String) -> Self { - Self { - service_client, - device_id, - device_content: serde_json::json!({}), - module_content: serde_json::json!({}), - modules_content: serde_json::json!({}), - } - } - - /// Sets the device content - /// - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// use serde_json; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let edge_configuration_builder = iot_hub.apply_on_edge_device("some-device").device_content(serde_json::json!({})); - /// ``` - pub fn device_content(mut self, device_content: serde_json::Value) -> Self { - self.device_content = device_content; - self - } - - /// Sets the module content - /// - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// use serde_json; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let edge_configuration_builder = iot_hub.apply_on_edge_device("some-device").module_content(serde_json::json!({})); - /// ``` - pub fn module_content(mut self, module_content: serde_json::Value) -> Self { - self.module_content = module_content; - self - } - - /// Sets the modules content - /// - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// use serde_json; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let edge_configuration_builder = iot_hub.apply_on_edge_device("some-device").modules_content(serde_json::json!({})); - /// ``` - pub fn modules_content(mut self, modules_content: serde_json::Value) -> Self { - self.modules_content = modules_content; - self - } - - /// Performs the apply on edge device request - /// - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// use serde_json; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// iot_hub.apply_on_edge_device("some-device").execute(); - /// ``` - pub async fn execute(self) -> azure_core::Result<()> { - let uri = format!( - "https://{}.azure-devices.net/devices/{}/applyConfigurationContent?api-version={}", - self.service_client.iot_hub_name, self.device_id, API_VERSION - ); - - let mut request = self.service_client.finalize_request(&uri, Method::Post)?; - let body = ApplyOnEdgeDeviceBody { - device_content: self.device_content, - module_content: self.module_content, - modules_content: self.modules_content, - }; - - let body = azure_core::to_json(&body)?; - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await?; - Ok(()) - } -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct ApplyOnEdgeDeviceBody { - device_content: serde_json::Value, - module_content: serde_json::Value, - modules_content: serde_json::Value, -} diff --git a/sdk/iot_hub/src/service/requests/create_or_update_configuration_builder.rs b/sdk/iot_hub/src/service/requests/create_or_update_configuration_builder.rs deleted file mode 100644 index 837ee6d177..0000000000 --- a/sdk/iot_hub/src/service/requests/create_or_update_configuration_builder.rs +++ /dev/null @@ -1,152 +0,0 @@ -use azure_core::headers; -use azure_core::Method; -use serde::Serialize; -use std::collections::HashMap; -use std::convert::TryInto; - -use crate::service::resources::{ConfigurationContent, ConfigurationMetrics}; -use crate::service::responses::ConfigurationResponse; -use crate::service::{ServiceClient, API_VERSION}; - -/// The CreateOrUpdateConfigurationBuilder is used to construct a new configuration -/// or update an existing one. -pub struct CreateOrUpdateConfigurationBuilder<'a> { - service_client: &'a ServiceClient, - configuration_id: String, - priority: u64, - target_condition: String, - etag: Option, - content: ConfigurationContent, - metrics: HashMap, - labels: HashMap, -} - -impl<'a> CreateOrUpdateConfigurationBuilder<'a> { - pub(crate) fn new( - service_client: &'a ServiceClient, - configuration_id: String, - priority: u64, - target_condition: String, - etag: Option, - ) -> Self { - Self { - service_client, - configuration_id, - priority, - target_condition, - etag, - content: ConfigurationContent { - device_content: None, - module_content: None, - modules_content: None, - }, - metrics: HashMap::new(), - labels: HashMap::new(), - } - } - - /// Sets the device content for the configuration - /// The content cannot be updated once it has been created. - pub fn device_content(mut self, device_content: serde_json::Value) -> Self { - self.content.device_content = Some(device_content); - self - } - - /// Sets the module content for the configuration. - /// The content cannot be updated once it has been created. - pub fn module_content(mut self, module_content: serde_json::Value) -> Self { - self.content.module_content = Some(module_content); - self - } - - /// Sets the module content for the configuration - /// The content cannot be updated once it has been created. - pub fn modules_content(mut self, modules_content: serde_json::Value) -> Self { - self.content.modules_content = Some(modules_content); - self - } - - /// Add a metric to the configuration - pub fn metric(mut self, key: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.metrics.insert(key.into(), value.into()); - self - } - - /// Add multiple metrics to the configuration. - pub fn metrics(mut self, metrics: HashMap) -> Self { - self.metrics = metrics; - self - } - - /// Add a label to the configuration. - pub fn label(mut self, key: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.labels.insert(key.into(), value.into()); - self - } - - /// Add multiple labels to the configuration. - pub fn labels(mut self, labels: HashMap) -> Self { - self.labels = labels; - self - } - - /// Performs the create or update request on the device identity - pub async fn execute(self) -> azure_core::Result { - let uri = format!( - "https://{}.azure-devices.net/configurations/{}?api-version={}", - self.service_client.iot_hub_name, &self.configuration_id, API_VERSION - ); - - let mut request = self.service_client.finalize_request(&uri, Method::Put)?; - - match &self.etag { - Some(etag) => { - request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); - } - None => (), - } - - let body = CreateOrUpdateConfigurationBody { - content: self.content, - etag: self.etag, - id: &self.configuration_id, - labels: self.labels, - metrics: ConfigurationMetrics { - queries: self.metrics, - results: HashMap::new(), - }, - priority: self.priority, - target_condition: &self.target_condition, - }; - - let body = azure_core::to_json(&body)?; - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct CreateOrUpdateConfigurationBody<'a, 'b> { - content: ConfigurationContent, - #[serde(skip_serializing_if = "Option::is_none")] - etag: Option, - id: &'a str, - labels: HashMap, - metrics: ConfigurationMetrics, - priority: u64, - target_condition: &'b str, -} diff --git a/sdk/iot_hub/src/service/requests/create_or_update_device_identity_builder.rs b/sdk/iot_hub/src/service/requests/create_or_update_device_identity_builder.rs deleted file mode 100644 index d3decacbf9..0000000000 --- a/sdk/iot_hub/src/service/requests/create_or_update_device_identity_builder.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::service::resources::{ - identity::DesiredCapability, identity::IdentityOperation, AuthenticationMechanism, - DeviceCapabilities, Status, -}; -use crate::service::responses::DeviceIdentityResponse; -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::error::{Error, ErrorKind}; -use azure_core::headers; -use azure_core::Method; -use serde::Serialize; -use std::convert::TryInto; - -/// The CreateOrUpdateDeviceIdentityBuilder is used to construct a new device identity -/// or the update an existing one. -pub struct CreateOrUpdateDeviceIdentityBuilder<'a> { - service_client: &'a ServiceClient, - capabilities: DeviceCapabilities, - etag: Option, - operation: IdentityOperation, -} - -impl<'a> CreateOrUpdateDeviceIdentityBuilder<'a> { - pub(crate) fn new( - service_client: &'a ServiceClient, - operation: IdentityOperation, - etag: Option, - ) -> Self { - Self { - service_client, - capabilities: DeviceCapabilities::default(), - etag, - operation, - } - } - - /// Sets a device capability on the device - pub fn device_capability(mut self, desired_capability: DesiredCapability) -> Self { - match desired_capability { - DesiredCapability::IotEdge => self.capabilities.iotedge = true, - } - self - } - - /// Performs the create or update request on the device identity - pub async fn execute( - self, - device_id: S, - status: Status, - authentication: AuthenticationMechanism, - ) -> azure_core::Result - where - S: AsRef, - { - let uri = format!( - "https://{}.azure-devices.net/devices/{}?api-version={}", - self.service_client.iot_hub_name, - device_id.as_ref(), - API_VERSION - ); - - let mut request = self.service_client.finalize_request(&uri, Method::Put)?; - - if self.operation == IdentityOperation::Update { - match &self.etag { - Some(etag) => { - request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); - } - None => return Err(Error::message(ErrorKind::Other, "etag is not set")), - } - } - - let body = CreateOrUpdateDeviceIdentityBody { - authentication, - device_id: device_id.as_ref(), - status, - capabilities: self.capabilities, - etag: self.etag, - }; - - let body = azure_core::to_json(&body)?; - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct CreateOrUpdateDeviceIdentityBody<'a> { - authentication: AuthenticationMechanism, - device_id: &'a str, - status: Status, - capabilities: DeviceCapabilities, - #[serde(skip_serializing_if = "Option::is_none")] - etag: Option, -} diff --git a/sdk/iot_hub/src/service/requests/create_or_update_module_identity_builder.rs b/sdk/iot_hub/src/service/requests/create_or_update_module_identity_builder.rs deleted file mode 100644 index f68d39ea2f..0000000000 --- a/sdk/iot_hub/src/service/requests/create_or_update_module_identity_builder.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::service::resources::{identity::IdentityOperation, AuthenticationMechanism}; -use crate::service::responses::ModuleIdentityResponse; -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::error::{Error, ErrorKind}; -use azure_core::headers; -use azure_core::Method; -use serde::Serialize; -use std::convert::TryInto; - -/// The CreateOrUpdateModuleIdentityBuilder is used to construct a new module identity -/// or the update an existing one. -pub struct CreateOrUpdateModuleIdentityBuilder<'a> { - service_client: &'a ServiceClient, - etag: Option, - operation: IdentityOperation, -} - -impl<'a> CreateOrUpdateModuleIdentityBuilder<'a> { - pub(crate) fn new( - service_client: &'a ServiceClient, - operation: IdentityOperation, - etag: Option, - ) -> Self { - Self { - service_client, - etag, - operation, - } - } - - /// Performs the create or update request on the device identity - pub async fn execute( - self, - device_id: S, - module_id: T, - managed_by: U, - authentication: AuthenticationMechanism, - ) -> azure_core::Result - where - S: AsRef, - T: AsRef, - U: AsRef, - { - let uri = format!( - "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", - self.service_client.iot_hub_name, - device_id.as_ref(), - module_id.as_ref(), - API_VERSION - ); - - let mut request = self.service_client.finalize_request(&uri, Method::Put)?; - - if self.operation == IdentityOperation::Update { - match &self.etag { - Some(etag) => { - request.insert_header(headers::IF_MATCH, format!("\"{}\"", etag)); - } - None => return Err(Error::message(ErrorKind::Other, "etag is not set")), - } - } - - let body = CreateOrUpdateModuleIdentityBody { - authentication, - device_id: device_id.as_ref(), - module_id: module_id.as_ref(), - managed_by: managed_by.as_ref(), - etag: self.etag, - }; - - let body = azure_core::to_json(&body)?; - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct CreateOrUpdateModuleIdentityBody<'a, 'b, 'c> { - authentication: AuthenticationMechanism, - device_id: &'a str, - module_id: &'b str, - managed_by: &'c str, - #[serde(skip_serializing_if = "Option::is_none")] - etag: Option, -} diff --git a/sdk/iot_hub/src/service/requests/delete_configuration_builder.rs b/sdk/iot_hub/src/service/requests/delete_configuration_builder.rs deleted file mode 100644 index 3411091253..0000000000 --- a/sdk/iot_hub/src/service/requests/delete_configuration_builder.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; - -use azure_core::headers; -use azure_core::Method; - -/// The DeleteConfigurationBuilder is used to construct a request to delete a configuration. -pub struct DeleteConfigurationBuilder<'a> { - service_client: &'a ServiceClient, - if_match: String, - configuration_id: String, -} - -impl<'a> DeleteConfigurationBuilder<'a> { - pub(crate) fn new( - service_client: &'a ServiceClient, - if_match: String, - configuration_id: String, - ) -> Self { - Self { - service_client, - if_match, - configuration_id, - } - } - - /// Execute the request to delete the configuration. - pub async fn execute(&self) -> azure_core::Result<()> { - let uri = format!( - "https://{}.azure-devices.net/configurations/{}?api-version={}", - self.service_client.iot_hub_name, self.configuration_id, API_VERSION - ); - - let mut request = self.service_client.finalize_request(&uri, Method::Delete)?; - request.insert_header(headers::IF_MATCH, format!("\"{}\"", &self.if_match)); - - request.set_body(azure_core::EMPTY_BODY); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await?; - Ok(()) - } -} diff --git a/sdk/iot_hub/src/service/requests/delete_identity_builder.rs b/sdk/iot_hub/src/service/requests/delete_identity_builder.rs deleted file mode 100644 index 7ca664cedd..0000000000 --- a/sdk/iot_hub/src/service/requests/delete_identity_builder.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::headers; -use azure_core::Method; - -/// The DeleteIdentityBuilder is used to construct a request to delete a module or device identity. -pub struct DeleteIdentityBuilder<'a> { - service_client: &'a ServiceClient, - if_match: String, - device_id: String, - module_id: Option, -} - -impl<'a> DeleteIdentityBuilder<'a> { - pub(crate) fn new( - service_client: &'a ServiceClient, - if_match: String, - device_id: String, - module_id: Option, - ) -> Self { - Self { - service_client, - if_match, - device_id, - module_id, - } - } - - /// Execute the request to delete the module or device identity. - pub async fn execute(&self) -> azure_core::Result<()> { - let uri = match &self.module_id { - Some(module_id) => format!( - "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", - self.service_client.iot_hub_name, self.device_id, module_id, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/devices/{}?api-version={}", - self.service_client.iot_hub_name, self.device_id, API_VERSION - ), - }; - - let mut request = self.service_client.finalize_request(&uri, Method::Delete)?; - request.insert_header(headers::IF_MATCH, format!("\"{}\"", &self.if_match)); - - request.set_body(azure_core::EMPTY_BODY); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await?; - Ok(()) - } -} diff --git a/sdk/iot_hub/src/service/requests/get_configuration.rs b/sdk/iot_hub/src/service/requests/get_configuration.rs deleted file mode 100644 index 69994207a3..0000000000 --- a/sdk/iot_hub/src/service/requests/get_configuration.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::error::Error; -use azure_core::Method; -use std::convert::{TryFrom, TryInto}; - -/// Execute the request to get the configuration of a given identifier. -pub(crate) async fn get_configuration( - service_client: &ServiceClient, - configuration_id: Option, -) -> azure_core::Result -where - T: TryFrom, -{ - let uri = match configuration_id { - Some(val) => format!( - "https://{}.azure-devices.net/configurations/{}?api-version={}", - service_client.iot_hub_name, val, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/configurations?api-version={}", - service_client.iot_hub_name, API_VERSION - ), - }; - - let mut request = service_client.finalize_request(&uri, Method::Get)?; - request.set_body(azure_core::EMPTY_BODY); - - service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() -} diff --git a/sdk/iot_hub/src/service/requests/get_identity.rs b/sdk/iot_hub/src/service/requests/get_identity.rs deleted file mode 100644 index 38433657ba..0000000000 --- a/sdk/iot_hub/src/service/requests/get_identity.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::error::Error; -use azure_core::Method; -use std::convert::{TryFrom, TryInto}; - -/// Execute the request to get the identity of a device or module. -pub(crate) async fn get_identity( - service_client: &ServiceClient, - device_id: String, - module_id: Option, -) -> azure_core::Result -where - T: TryFrom, -{ - let uri = match module_id { - Some(module_id) => format!( - "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", - service_client.iot_hub_name, device_id, module_id, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/devices/{}?api-version={}", - service_client.iot_hub_name, device_id, API_VERSION - ), - }; - - let mut request = service_client.finalize_request(&uri, Method::Get)?; - request.set_body(azure_core::EMPTY_BODY); - - service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() -} diff --git a/sdk/iot_hub/src/service/requests/get_twin.rs b/sdk/iot_hub/src/service/requests/get_twin.rs deleted file mode 100644 index 4aca9519d0..0000000000 --- a/sdk/iot_hub/src/service/requests/get_twin.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::error::Error; -use azure_core::Method; -use std::convert::TryFrom; -use std::convert::TryInto; - -/// Execute the request to get the twin of a module or device. -pub(crate) async fn get_twin( - service_client: &ServiceClient, - device_id: String, - module_id: Option, -) -> azure_core::Result -where - T: TryFrom, -{ - let uri = match module_id { - Some(val) => format!( - "https://{}.azure-devices.net/twins/{}/modules/{}?api-version={}", - service_client.iot_hub_name, device_id, val, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/twins/{}?api-version={}", - service_client.iot_hub_name, device_id, API_VERSION - ), - }; - - let mut request = service_client.finalize_request(&uri, Method::Get)?; - request.set_body(azure_core::EMPTY_BODY); - - service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() -} diff --git a/sdk/iot_hub/src/service/requests/invoke_method_builder.rs b/sdk/iot_hub/src/service/requests/invoke_method_builder.rs deleted file mode 100644 index 70ecc5aed6..0000000000 --- a/sdk/iot_hub/src/service/requests/invoke_method_builder.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::service::responses::InvokeMethodResponse; -use crate::service::{ServiceClient, API_VERSION}; -use azure_core::Method; -use serde::Serialize; -use std::convert::TryInto; - -/// The InvokeMethodBuilder is used for constructing the request to -/// invoke a module or device method. -pub struct InvokeMethodBuilder<'a> { - iot_hub_service: &'a ServiceClient, - device_id: String, - module_id: Option, - method_name: String, - connect_time_out: u64, - response_time_out: u64, -} - -impl<'a> InvokeMethodBuilder<'a> { - /// Create a new DirectMethod - pub(crate) fn new( - iot_hub_service: &'a ServiceClient, - device_id: String, - module_id: Option, - method_name: String, - response_time_out: u64, - connect_time_out: u64, - ) -> Self { - Self { - iot_hub_service, - device_id, - module_id, - method_name, - connect_time_out, - response_time_out, - } - } - - /// Invoke the DirectMethod - /// - /// Either a module method, or device method is invoked based on the - /// way the DirectMethod was created. On invocation a DirectMethodResponse - /// is returned. This does not mean the invocation was successfull. The status - /// code within the DirectMethodResponse should still be verified. - /// - /// # Examples - /// ``` - /// # use std::sync::Arc; - /// # use azure_core::HttpClient; - /// use azure_iot_hub::service::ServiceClient; - /// # let http_client = azure_core::new_http_client(); - /// - /// let service = ServiceClient::from_sas_token(http_client, "some-iot-hub", "sas_token"); - /// let great_method = service.create_device_method( - /// "SomeDeviceId", - /// "GreatMethod", - /// 100, - /// 60 - /// ); - /// - /// great_method.execute(serde_json::json!({"hello": "world"})); - /// ``` - pub async fn execute( - &self, - payload: serde_json::Value, - ) -> azure_core::Result { - let uri = match &self.module_id { - Some(module_id_value) => format!( - "https://{}.azure-devices.net/twins/{}/modules/{}/methods?api-version={}", - self.iot_hub_service.iot_hub_name, self.device_id, module_id_value, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/twins/{}/methods?api-version={}", - self.iot_hub_service.iot_hub_name, self.device_id, API_VERSION - ), - }; - - let mut request = self.iot_hub_service.finalize_request(&uri, Method::Post)?; - let method = InvokeMethodBody { - connect_timeout_in_seconds: self.connect_time_out, - method_name: &self.method_name, - payload, - response_timeout_in_seconds: self.response_time_out, - }; - - let body = azure_core::to_json(&method)?; - - request.set_body(body); - - self.iot_hub_service - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} - -/// Body for the InvokeMethod request -#[derive(Serialize, Debug)] -#[serde(rename_all = "camelCase")] -struct InvokeMethodBody<'a> { - connect_timeout_in_seconds: u64, - method_name: &'a str, - payload: serde_json::Value, - response_timeout_in_seconds: u64, -} - -#[cfg(test)] -mod tests { - use crate::service::ServiceClient; - - #[test] - fn directmethod_new_should_succeed() { - use crate::service::InvokeMethodBuilder; - - let http_client = azure_core::new_http_client(); - let service: ServiceClient = ServiceClient::from_sas_token(http_client, "test", "test"); - let direct_method = InvokeMethodBuilder::new( - &service, - "SomeDevice".to_string(), - None, - "GreatMethod".to_string(), - 20, - 10, - ); - assert_eq!(direct_method.device_id, "SomeDevice"); - assert_eq!(direct_method.module_id, None); - assert_eq!(direct_method.method_name, "GreatMethod"); - assert_eq!(direct_method.connect_time_out, 10); - assert_eq!(direct_method.response_time_out, 20); - } -} diff --git a/sdk/iot_hub/src/service/requests/mod.rs b/sdk/iot_hub/src/service/requests/mod.rs deleted file mode 100644 index a2c5c2f8b9..0000000000 --- a/sdk/iot_hub/src/service/requests/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -mod apply_on_edge_device_builder; -mod create_or_update_configuration_builder; -mod create_or_update_device_identity_builder; -mod create_or_update_module_identity_builder; -mod delete_configuration_builder; -mod delete_identity_builder; -mod get_configuration; -mod get_identity; -mod get_twin; -mod invoke_method_builder; -mod query_builder; -mod update_or_replace_twin_builder; - -pub use apply_on_edge_device_builder::ApplyOnEdgeDeviceBuilder; -pub use create_or_update_configuration_builder::CreateOrUpdateConfigurationBuilder; -pub use create_or_update_device_identity_builder::CreateOrUpdateDeviceIdentityBuilder; -pub use create_or_update_module_identity_builder::CreateOrUpdateModuleIdentityBuilder; -pub use delete_configuration_builder::DeleteConfigurationBuilder; -pub use delete_identity_builder::DeleteIdentityBuilder; -pub(crate) use get_configuration::get_configuration; -pub(crate) use get_identity::get_identity; -pub(crate) use get_twin::get_twin; -pub use invoke_method_builder::InvokeMethodBuilder; -pub use query_builder::QueryBuilder; -pub use update_or_replace_twin_builder::UpdateOrReplaceTwinBuilder; diff --git a/sdk/iot_hub/src/service/requests/query_builder.rs b/sdk/iot_hub/src/service/requests/query_builder.rs deleted file mode 100644 index 3070895693..0000000000 --- a/sdk/iot_hub/src/service/requests/query_builder.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![allow(missing_docs)] - -use crate::service::{responses::QueryResponse, ServiceClient, API_VERSION}; -use azure_core::prelude::*; -use azure_core::Method; -use serde::Serialize; -use std::convert::TryInto; - -/// Body for the Query request -#[derive(Serialize, Debug)] -struct QueryBody { - query: String, -} - -/// Builder for creating queries -pub struct QueryBuilder<'a> { - service_client: &'a ServiceClient, - max_item_count: MaxItemCount, - continuation: Option, -} - -impl<'a> QueryBuilder<'a> { - /// Create a new query struct - pub(crate) fn new(service_client: &'a ServiceClient) -> Self { - Self { - service_client, - max_item_count: MaxItemCount::new(-1), - continuation: None, - } - } - - azure_core::setters! { - max_item_count: i32 => MaxItemCount::new(max_item_count), - continuation: Continuation => Some(continuation), - } - - /// Invoke a qiven query on the IoT Hub - /// - /// ``` - /// use std::sync::Arc; - /// use azure_core::HttpClient; - /// use azure_iot_hub::service::ServiceClient; - /// - /// # let http_client = azure_core::new_http_client(); - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let query_builder = iot_hub.query().max_item_count(1).continuation("some_token").execute("SELECT * FROM devices"); - /// ``` - pub async fn execute(self, query: S) -> azure_core::Result - where - S: Into, - { - let uri = format!( - "https://{}.azure-devices.net/devices/query?api-version={}", - self.service_client.iot_hub_name, API_VERSION - ); - - let query_body = QueryBody { - query: query.into(), - }; - let body = azure_core::to_json(&query_body)?; - - let mut request = self.service_client.finalize_request(&uri, Method::Post)?; - request.add_optional_header(&self.continuation); - request.add_mandatory_header(&self.max_item_count); - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} diff --git a/sdk/iot_hub/src/service/requests/update_or_replace_twin_builder.rs b/sdk/iot_hub/src/service/requests/update_or_replace_twin_builder.rs deleted file mode 100644 index a6e87a7b82..0000000000 --- a/sdk/iot_hub/src/service/requests/update_or_replace_twin_builder.rs +++ /dev/null @@ -1,175 +0,0 @@ -use azure_core::error::Error; -use azure_core::headers; -use azure_core::Method; -use serde::Serialize; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::convert::TryInto; -use std::marker::PhantomData; - -use crate::service::{ServiceClient, API_VERSION}; - -/// The UpdateOrReplaceTwinBuilder is used to construct a request for -/// updating or replacing a device or module twin. -pub struct UpdateOrReplaceTwinBuilder<'a, R> -where - R: TryFrom, -{ - service_client: &'a ServiceClient, - pub(crate) device_id: String, - pub(crate) module_id: Option, - if_match: Option, - desired_properties: Option, - desired_tags: HashMap, - pub(crate) method: Method, - desired_twin_return_type: PhantomData, -} - -impl<'a, R> UpdateOrReplaceTwinBuilder<'a, R> -where - R: TryFrom, -{ - pub(crate) fn new( - service_client: &'a ServiceClient, - device_id: String, - module_id: Option, - method: Method, - ) -> Self { - Self { - service_client, - device_id, - module_id, - if_match: None, - desired_properties: None, - desired_tags: HashMap::new(), - method, - desired_twin_return_type: PhantomData, - } - } - - /// Add a new tag to the desired twin. - /// - /// This function can be invoked multiple times to add multiple tags to the desired twin. - /// When adding a tag which is already in the desired twin, its value will be updated. - /// - /// # Example - /// ``` - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// use azure_iot_hub::service::ServiceClient; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let twin = iot_hub.update_device_twin("some-device") - /// .tag("TagName", "TagValue") - /// .tag("AnotherTag", "WithAnotherValue") - /// .tag("LastTag", "LastValue"); - /// ``` - pub fn tag(mut self, tag_name: T, tag_value: T) -> Self - where - T: Into, - { - self.desired_tags.insert(tag_name.into(), tag_value.into()); - self - } - - /// Add new properties to the desired twin - /// - /// # Example - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// # let http_client = azure_core::new_http_client(); - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let twin = iot_hub.update_device_twin("some-device") - /// .properties(serde_json::json!({ - /// "PropertyName": "PropertyValue", - /// "ParentProperty": { - /// "ChildProperty": "ChildValue" - /// } - /// })); - pub fn properties(mut self, desired_properties: serde_json::Value) -> Self { - self.desired_properties = Some(desired_properties); - self - } - - /// Set the ETag for the twin - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let twin = iot_hub.update_device_twin("some-device") - /// .if_match("AAAAAAAAAAA="); - /// ``` - pub fn if_match(mut self, if_match: T) -> Self - where - T: Into, - { - self.if_match = Some(if_match.into()); - self - } - - /// Updates the twin with the desired settings - /// - /// ``` - /// use azure_iot_hub::service::ServiceClient; - /// - /// # let connection_string = "HostName=cool-iot-hub.azure-devices.net;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - /// # let http_client = azure_core::new_http_client(); - /// let iot_hub = ServiceClient::from_connection_string(http_client, connection_string, 3600).expect("Failed to create the ServiceClient!"); - /// let twin = iot_hub.update_device_twin("some-device") - /// .tag("TagName", "TagValue") - /// .properties(serde_json::json!({"PropertyName": "PropertyValue"})) - /// .execute(); - /// ``` - pub async fn execute(self) -> azure_core::Result { - let body = DesiredTwinBody { - tags: self.desired_tags, - properties: DesiredTwinProperties { - desired: self - .desired_properties - .unwrap_or_else(|| serde_json::json!({})), - }, - }; - - let uri = match self.module_id { - Some(val) => format!( - "https://{}.azure-devices.net/twins/{}/modules/{}?api-version={}", - self.service_client.iot_hub_name, self.device_id, val, API_VERSION - ), - None => format!( - "https://{}.azure-devices.net/twins/{}?api-version={}", - self.service_client.iot_hub_name, self.device_id, API_VERSION - ), - }; - - let mut request = self.service_client.finalize_request(&uri, self.method)?; - if let Some(if_match) = self.if_match { - request.insert_header(headers::IF_MATCH, format!("\"{}\"", if_match)); - } - let body = azure_core::to_json(&body)?; - - request.set_body(body); - - self.service_client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() - } -} - -#[derive(Serialize)] -struct DesiredTwinProperties { - desired: serde_json::Value, -} - -#[derive(Serialize)] -struct DesiredTwinBody { - tags: HashMap, - properties: DesiredTwinProperties, -} diff --git a/sdk/iot_hub/src/service/resources/configuration.rs b/sdk/iot_hub/src/service/resources/configuration.rs index 0116052202..4468a1298a 100644 --- a/sdk/iot_hub/src/service/resources/configuration.rs +++ b/sdk/iot_hub/src/service/resources/configuration.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// The configuration content for devices or modules on edge devices. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct ConfigurationContent { /// The device configuration content. diff --git a/sdk/iot_hub/src/service/resources/identity.rs b/sdk/iot_hub/src/service/resources/identity.rs index e01ae61c2d..3e4dee0f9e 100644 --- a/sdk/iot_hub/src/service/resources/identity.rs +++ b/sdk/iot_hub/src/service/resources/identity.rs @@ -16,7 +16,7 @@ pub enum ConnectionState { } /// Device or module status -#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Status { /// The device or module is disabled @@ -26,7 +26,7 @@ pub enum Status { } /// Representation of device capabilities. -#[derive(Default, Serialize, Deserialize, Debug, PartialEq)] +#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct DeviceCapabilities { #[serde(rename = "iotEdge")] /// Whether the device has the IoT Edge capability or not. @@ -34,7 +34,7 @@ pub struct DeviceCapabilities { } /// Representation of a symmetric key for authentication. -#[derive(Serialize, Deserialize, Debug, PartialEq, Default)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] pub struct SymmetricKey { /// The primary key. pub primary_key: Option, @@ -43,7 +43,7 @@ pub struct SymmetricKey { } /// Representation of a x509 thumbprint for authentication. -#[derive(Default, Serialize, Deserialize, Debug, PartialEq)] +#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct X509ThumbPrint { /// The primary thumbprint. @@ -53,7 +53,7 @@ pub struct X509ThumbPrint { } /// AuthenticationType of a module or device. -#[derive(Serialize, Debug, Deserialize, PartialEq)] +#[derive(Serialize, Debug, Deserialize, Clone, PartialEq)] pub enum AuthenticationType { /// Authentication using a certificate authority. #[serde(rename = "certificateAuthority")] @@ -70,7 +70,7 @@ pub enum AuthenticationType { } /// The authentication mechanism for a device or module identity. -#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct AuthenticationMechanism { /// The symmetric key pair used for authentication. @@ -126,7 +126,7 @@ impl AuthenticationMechanism { } /// The operation to perform on an identity -#[derive(PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub(crate) enum IdentityOperation { Create, Update,