diff --git a/sdk/core/src/policies/mod.rs b/sdk/core/src/policies/mod.rs index 66dc215c49..aeda65088b 100644 --- a/sdk/core/src/policies/mod.rs +++ b/sdk/core/src/policies/mod.rs @@ -1,11 +1,13 @@ mod custom_headers_policy; mod retry_policies; mod telemetry_policy; +mod timeout_policy; mod transport; pub use custom_headers_policy::{CustomHeaders, CustomHeadersPolicy}; pub use retry_policies::*; pub use telemetry_policy::*; +pub use timeout_policy::*; pub use transport::*; use crate::{Context, Request, Response}; diff --git a/sdk/storage/src/core/timeout_policy.rs b/sdk/core/src/policies/timeout_policy.rs similarity index 87% rename from sdk/storage/src/core/timeout_policy.rs rename to sdk/core/src/policies/timeout_policy.rs index 7e08e0f2f2..fcae779d9f 100644 --- a/sdk/storage/src/core/timeout_policy.rs +++ b/sdk/core/src/policies/timeout_policy.rs @@ -1,7 +1,7 @@ +use crate::request_options::Timeout; +use crate::{AppendToUrlQuery, Context, Policy, PolicyResult, Request}; use std::sync::Arc; -use azure_core::{prelude::*, Context, Policy, PolicyResult, Request}; - #[derive(Debug, Clone, Default)] pub struct TimeoutPolicy { default_timeout: Option, diff --git a/sdk/iot_hub/Cargo.toml b/sdk/iot_hub/Cargo.toml index b1ab9ecc68..3d3fa7ea27 100644 --- a/sdk/iot_hub/Cargo.toml +++ b/sdk/iot_hub/Cargo.toml @@ -7,6 +7,7 @@ description = "Azure IoT Hub" license = "MIT" [dependencies] +async-trait = "0.1" azure_core = { path = "../core", version = "0.3", default_features = false } base64 = "0.13" bytes = "1.0" @@ -28,4 +29,4 @@ reqwest = "0.11.0" tokio = { version = "1.0", features = ["macros"] } [features] -default = ["azure_core/default"] \ No newline at end of file +default = ["azure_core/default"] 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 40dfa03fa6..8087d82dce 100644 --- a/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs +++ b/sdk/iot_hub/examples/apply_configuration_on_edge_device.rs @@ -56,9 +56,7 @@ 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 service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; service_client .apply_on_edge_device(device_id) .modules_content(modules_content) diff --git a/sdk/iot_hub/examples/configuration.rs b/sdk/iot_hub/examples/configuration.rs index 8718c633de..94c05438e9 100644 --- a/sdk/iot_hub/examples/configuration.rs +++ b/sdk/iot_hub/examples/configuration.rs @@ -1,4 +1,4 @@ -use azure_iot_hub::service::{resources::Configuration, ServiceClient}; +use azure_iot_hub::service::ServiceClient; use std::error::Error; #[tokio::main] @@ -10,9 +10,7 @@ async fn main() -> Result<(), Box> { .nth(1) .expect("Please pass the configuration id as the first parameter"); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; println!("Creating a new configuration with id: {}", configuration_id); @@ -42,7 +40,6 @@ async fn main() -> Result<(), Box> { .get_configuration(configuration_id) .into_future() .await?; - let configuration: Configuration = configuration.try_into()?; println!( "Successfully retrieved the new configuration '{:?}'", diff --git a/sdk/iot_hub/examples/device_identity.rs b/sdk/iot_hub/examples/device_identity.rs index 194eb4b083..04b1272129 100644 --- a/sdk/iot_hub/examples/device_identity.rs +++ b/sdk/iot_hub/examples/device_identity.rs @@ -13,9 +13,7 @@ async fn main() -> Result<(), Box> { .expect("Please pass the device id as the first parameter"); println!("Getting device twin for device '{}'", device_id); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; let device = service_client .create_device_identity( &device_id, @@ -27,6 +25,7 @@ async fn main() -> Result<(), Box> { ) .into_future() .await?; + let device: DeviceIdentityResponse = device.try_into()?; println!("Successfully created a new device '{}'", device.device_id); diff --git a/sdk/iot_hub/examples/directmethod.rs b/sdk/iot_hub/examples/directmethod.rs index 4f8835a3b9..06c1e70024 100644 --- a/sdk/iot_hub/examples/directmethod.rs +++ b/sdk/iot_hub/examples/directmethod.rs @@ -23,9 +23,7 @@ async fn main() -> Result<(), Box> { .nth(4) .expect("Please pass the payload as the fourth parameter"); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; println!( "Sending direct method {} to {}:{} on: {}", method_name, device_id, module_id, service_client.iot_hub_name diff --git a/sdk/iot_hub/examples/gettwin.rs b/sdk/iot_hub/examples/gettwin.rs index 59dc56f94c..13b4f7c2d3 100644 --- a/sdk/iot_hub/examples/gettwin.rs +++ b/sdk/iot_hub/examples/gettwin.rs @@ -12,9 +12,7 @@ async fn main() -> Result<(), Box> { println!("Getting device twin for device: {}", device_id); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; let twin = service_client .get_device_twin(device_id) .into_future() diff --git a/sdk/iot_hub/examples/module_identity.rs b/sdk/iot_hub/examples/module_identity.rs index 3f5f3c100d..abe7217c00 100644 --- a/sdk/iot_hub/examples/module_identity.rs +++ b/sdk/iot_hub/examples/module_identity.rs @@ -16,9 +16,7 @@ async fn main() -> Result<(), Box> { .nth(2) .expect("Please pass the module id as the second parameter"); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; let module = service_client .create_module_identity( &device_id, diff --git a/sdk/iot_hub/examples/query_iothub.rs b/sdk/iot_hub/examples/query_iothub.rs index 3cf75b771b..d7d8837a94 100644 --- a/sdk/iot_hub/examples/query_iothub.rs +++ b/sdk/iot_hub/examples/query_iothub.rs @@ -11,9 +11,7 @@ async fn main() -> Result<(), Box> { let query = "SELECT * FROM devices"; println!("Invoking query '{}' on the IoT Hub", query); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; let response = service_client .query(query) diff --git a/sdk/iot_hub/examples/updatetwin.rs b/sdk/iot_hub/examples/updatetwin.rs index bdf2ebc006..aa2028aaa8 100644 --- a/sdk/iot_hub/examples/updatetwin.rs +++ b/sdk/iot_hub/examples/updatetwin.rs @@ -16,10 +16,8 @@ async fn main() -> Result<(), Box> { .expect("Please pass the payload as the second parameter"); println!("Updating device twin for device: {}", device_id); - let http_client = azure_core::new_http_client(); - let service_client = - ServiceClient::from_connection_string(http_client, iot_hub_connection_string, 3600)?; + let service_client = ServiceClient::new_connection_string(iot_hub_connection_string, 3600)?; let updated_twin = service_client .update_device_twin(device_id) .desired_properties(serde_json::from_str(&payload)?) diff --git a/sdk/iot_hub/src/authorization_policy.rs b/sdk/iot_hub/src/authorization_policy.rs new file mode 100644 index 0000000000..856425e3d2 --- /dev/null +++ b/sdk/iot_hub/src/authorization_policy.rs @@ -0,0 +1,60 @@ +use crate::service::IoTHubCredentials; +use azure_core::error::{ErrorKind, ResultExt}; +use azure_core::{ + headers::{self, *}, + Context, Policy, PolicyResult, Request, +}; +use std::sync::Arc; + +const IOTHUB_TOKEN_SCOPE: &str = "https://iothubs.azure.net"; + +#[derive(Debug, Clone)] +pub struct AuthorizationPolicy { + credentials: IoTHubCredentials, +} + +impl AuthorizationPolicy { + pub(crate) fn new(credentials: IoTHubCredentials) -> Self { + Self { credentials } + } +} + +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +impl Policy for AuthorizationPolicy { + async fn send( + &self, + ctx: &Context, + request: &mut Request, + next: &[Arc], + ) -> PolicyResult { + assert!( + !next.is_empty(), + "Authorization policies cannot be the last policy of a pipeline" + ); + let request = match &self.credentials { + IoTHubCredentials::SASToken(sas_token) => { + request.insert_header(headers::AUTHORIZATION, sas_token); + request + } + IoTHubCredentials::BearerToken(token) => { + request.insert_header(AUTHORIZATION, format!("Bearer {}", token)); + request + } + IoTHubCredentials::TokenCredential(token_credential) => { + let bearer_token = token_credential + .get_token(IOTHUB_TOKEN_SCOPE) + .await + .context(ErrorKind::Credential, "failed to get bearer token")?; + + request.insert_header( + AUTHORIZATION, + format!("Bearer {}", bearer_token.token.secret()), + ); + request + } + }; + + next[0].send(ctx, request, &next[1..]).await + } +} diff --git a/sdk/iot_hub/src/lib.rs b/sdk/iot_hub/src/lib.rs index 730d26de90..8b8d320c45 100644 --- a/sdk/iot_hub/src/lib.rs +++ b/sdk/iot_hub/src/lib.rs @@ -2,5 +2,6 @@ #![deny(missing_docs)] //! The IoT Hub crate contains a client that can be used to manage the IoT Hub. +mod authorization_policy; /// The service module contains the IoT Hub Service Client that can be used to manage the IoT Hub. pub mod service; diff --git a/sdk/iot_hub/src/service/mod.rs b/sdk/iot_hub/src/service/mod.rs index 6ae5050879..557ff6d1e7 100644 --- a/sdk/iot_hub/src/service/mod.rs +++ b/sdk/iot_hub/src/service/mod.rs @@ -1,6 +1,10 @@ +use crate::authorization_policy::AuthorizationPolicy; use azure_core::error::{Error, ErrorKind, ResultExt}; use azure_core::request_options::ContentType; -use azure_core::{headers, CollectedResponse, HttpClient, Method, Request, Url}; +use azure_core::{ + auth::TokenCredential, prelude::Timeout, ClientOptions, CollectedResponse, Context, Method, + Pipeline, Request, Response, TimeoutPolicy, Url, +}; use base64::{decode, encode_config}; use hmac::{Hmac, Mac}; use sha2::Sha256; @@ -29,6 +33,36 @@ use self::resources::{AuthenticationMechanism, Status}; /// The API version to use for any requests pub const API_VERSION: &str = "2020-05-31-preview"; +/// Credential for authorizing requests against IoT Hub +#[derive(Clone)] +pub enum IoTHubCredentials { + /// Authorize via SAS token + SASToken(String), + /// Authorize via BearerToken token + BearerToken(String), + /// Authorize using a TokenCredential + TokenCredential(Arc), +} + +impl std::fmt::Debug for IoTHubCredentials { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + IoTHubCredentials::SASToken(_) => f + .debug_struct("IoTHubCredentials") + .field("credential", &"SASToken") + .finish(), + IoTHubCredentials::BearerToken(_) => f + .debug_struct("IoTHubCredentials") + .field("credential", &"BearerToken") + .finish(), + IoTHubCredentials::TokenCredential(_) => f + .debug_struct("IoTHubCredentials") + .field("credential", &"TokenCredential") + .finish(), + } + } +} + /// The ServiceClient is the main entry point for communicating with the IoT Hub. /// /// There are several ways to construct the IoTHub Service object. Either by: @@ -38,11 +72,9 @@ pub const API_VERSION: &str = "2020-05-31-preview"; /// use to communicate with the IoT Hub. #[derive(Clone, Debug)] pub struct ServiceClient { - http_client: Arc, /// The name of the IoT Hub. pub iot_hub_name: String, - /// The SAS token that is used for authentication. - pub(crate) sas_token: String, + pipeline: Pipeline, } impl ServiceClient { @@ -51,28 +83,25 @@ impl ServiceClient { /// # Example /// ``` /// use std::sync::Arc; - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// - /// let http_client = azure_core::new_http_client(); /// let iot_hub_name = "cool-iot-hub"; /// let sas_token = ""; /// - /// let iot_hub = ServiceClient::from_sas_token(http_client, iot_hub_name, sas_token); + /// let iot_hub = ServiceClient::new_sas_token(iot_hub_name, sas_token); /// ``` - pub fn from_sas_token( - http_client: Arc, - iot_hub_name: S, - sas_token: T, - ) -> Self + pub fn new_sas_token(iot_hub_name: S, sas_token: T) -> Self where S: Into, T: Into, { + let pipeline = new_pipeline_from_options( + ServiceOptions::default(), + IoTHubCredentials::SASToken(sas_token.into()), + ); Self { - http_client, iot_hub_name: iot_hub_name.into(), - sas_token: sas_token.into(), + pipeline, } } @@ -119,20 +148,16 @@ impl ServiceClient { /// The private key should preferably be of a user / group that has the rights to make service requests. /// ``` /// use std::sync::Arc; - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// - /// let http_client = azure_core::new_http_client(); - /// /// let iot_hub_name = "iot-hub"; /// let key_name = "iot_hubowner"; /// let private_key = "YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; /// - /// let result = ServiceClient::from_private_key(http_client, iot_hub_name, key_name, private_key, 3600); + /// let result = ServiceClient::new_private_key(iot_hub_name, key_name, private_key, 3600); /// assert!(result.is_ok()); /// ``` - pub fn from_private_key( - http_client: Arc, + pub fn new_private_key( iot_hub_name: S, key_name: T, private_key: U, @@ -152,10 +177,14 @@ impl ServiceClient { expires_in_seconds, )?; + let pipeline = new_pipeline_from_options( + ServiceOptions::default(), + IoTHubCredentials::SASToken(sas_token), + ); + Ok(Self { - http_client, iot_hub_name: iot_hub_name_str, - sas_token, + pipeline, }) } @@ -164,17 +193,14 @@ impl ServiceClient { /// The connection string should preferably be from a user / group that has the rights to make service requests. /// ``` /// 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 result = ServiceClient::from_connection_string(http_client, connection_string, 3600); + /// let result = ServiceClient::new_connection_string(connection_string, 3600); /// assert!(result.is_ok()); /// ``` - pub fn from_connection_string( - http_client: Arc, + pub fn new_connection_string( connection_string: S, expires_in_seconds: u64, ) -> azure_core::Result @@ -241,22 +267,56 @@ impl ServiceClient { Self::generate_sas_token(iot_hub_name, key_name, primary_key, expires_in_seconds) .context(ErrorKind::Other, "generate SAS token error")?; + let pipeline = new_pipeline_from_options( + ServiceOptions::default(), + IoTHubCredentials::SASToken(sas_token), + ); + Ok(Self { - http_client, iot_hub_name: iot_hub_name.to_string(), - sas_token, + pipeline, }) } + /// Create a new IoTHubService struct with a TokenCredential + pub fn new_token_credential( + iot_hub_name: A, + token_credential: Arc, + ) -> Self + where + A: Into, + { + let credentials = IoTHubCredentials::TokenCredential(token_credential); + let pipeline = new_pipeline_from_options(ServiceOptions::default(), credentials); + + Self { + iot_hub_name: iot_hub_name.into(), + pipeline, + } + } + + /// Create a new IoTHubService struct with a BearerToken + pub fn new_bearer_token(iot_hub_name: A, bearer_token: BT) -> Self + where + A: Into, + BT: Into, + { + let credentials = IoTHubCredentials::BearerToken(bearer_token.into()); + let pipeline = new_pipeline_from_options(ServiceOptions::default(), credentials); + + Self { + iot_hub_name: iot_hub_name.into(), + pipeline, + } + } + /// Create a new device method /// /// ``` - /// 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 service client!"); + /// let iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the service client!"); /// let device_method = iot_hub.create_device_method("some-device", "hello-world", serde_json::json!({})); /// ``` pub fn create_device_method( @@ -275,12 +335,10 @@ impl ServiceClient { /// Create a new module method /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device_method = iot_hub.create_module_method("some-device", "some-module", "hello-world", serde_json::json!({})); /// ``` pub fn create_module_method( @@ -302,12 +360,10 @@ impl ServiceClient { /// Get the module twin of a given device and module /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.get_module_twin("some-device", "some-module"); /// ``` pub fn get_module_twin(&self, device_id: S, module_id: T) -> GetTwinBuilder @@ -321,12 +377,10 @@ impl ServiceClient { /// Get the device twin of a given device /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.get_device_twin("some-device"); /// ``` pub fn get_device_twin(&self, device_id: S) -> GetTwinBuilder @@ -339,12 +393,10 @@ impl ServiceClient { /// Update the module twin of a given device or module /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.update_module_twin("some-device", "some-module") /// .tag("TagName", "TagValue") /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) @@ -362,12 +414,10 @@ impl ServiceClient { /// Replace the module twin of a given device and module /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.replace_module_twin("some-device", "some-module") /// .tag("TagName", "TagValue") /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) @@ -389,12 +439,10 @@ impl ServiceClient { /// Update the device twin of a given device /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(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"})) @@ -410,12 +458,10 @@ impl ServiceClient { /// Replace the device twin of a given device /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.replace_device_twin("some-device") /// .tag("TagName", "TagValue") /// .desired_properties(serde_json::json!({"PropertyName": "PropertyValue"})) @@ -431,12 +477,10 @@ impl ServiceClient { /// Get the identity of a given device /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_device_identity("some-device"); /// ``` pub fn get_device_identity(&self, device_id: S) -> GetIdentityBuilder @@ -449,13 +493,11 @@ impl ServiceClient { /// Create a new device identity /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.create_device_identity("some-existing-device", Status::Enabled, AuthenticationMechanism::new_using_symmetric_key("first-key", "second-key")) /// .into_future(); /// ``` @@ -481,13 +523,11 @@ impl ServiceClient { /// Update an existing device identity /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// 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( @@ -517,12 +557,10 @@ impl ServiceClient { /// an unconditional delete will be performed. /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(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 @@ -536,12 +574,10 @@ impl ServiceClient { /// Get the identity of a given module /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_module_identity("some-device", "some-module"); /// ``` pub fn get_module_identity(&self, device_id: S, module_id: T) -> GetIdentityBuilder @@ -555,13 +591,11 @@ impl ServiceClient { /// Create a new module identity /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// 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( @@ -590,13 +624,11 @@ impl ServiceClient { /// Update an existing module identity /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// 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( @@ -630,12 +662,10 @@ impl ServiceClient { /// an unconditional delete will be performed. /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.delete_module_identity("some-device-id", "some-module-id", "some-etag"); /// ``` pub fn delete_module_identity( @@ -660,12 +690,10 @@ impl ServiceClient { /// Invoke a query /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let query_builder = iot_hub.query("$SOME_QUERY"); /// ``` pub fn query(&self, query: Q) -> QueryBuilder @@ -678,12 +706,10 @@ impl ServiceClient { /// Apply configuration on an Edge device /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let edge_configuration_builder = iot_hub.apply_on_edge_device("some-device"); /// ``` pub fn apply_on_edge_device(&self, device_id: S) -> ApplyOnEdgeDeviceBuilder @@ -696,12 +722,10 @@ impl ServiceClient { /// Get a configuration /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_configuration("some-configuration"); /// ``` pub fn get_configuration(&self, configuration_id: S) -> GetConfigurationBuilder @@ -714,12 +738,10 @@ impl ServiceClient { /// Get all configurations /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.get_configurations(); /// ``` pub fn get_configurations(&self) -> GetConfigurationBuilder { @@ -729,13 +751,11 @@ impl ServiceClient { /// Create a new configuration. /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let configuration = iot_hub.create_configuration("some-configuration-id", 10, "tags.environment='test'") /// .into_future(); /// ``` @@ -761,13 +781,11 @@ impl ServiceClient { /// Update a configuration. /// /// ``` - /// use azure_core::HttpClient; /// use azure_iot_hub::service::ServiceClient; /// use azure_iot_hub::service::resources::{Status, AuthenticationMechanism}; /// - /// # 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 iot_hub = ServiceClient::new_connection_string(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") /// .into_future(); /// ``` @@ -798,12 +816,10 @@ impl ServiceClient { /// an unconditional delete will be performed. /// /// ``` - /// 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let device = iot_hub.delete_configuration("some-configuration-id", "some-etag"); /// ``` pub fn delete_configuration( @@ -825,14 +841,52 @@ impl ServiceClient { method: Method, ) -> azure_core::Result { let mut request = Request::new(Url::parse(uri)?, method); - request.insert_header(headers::AUTHORIZATION, &self.sas_token); 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() + /// send the request via the request pipeline + pub async fn send( + &self, + context: &mut Context, + request: &mut Request, + ) -> azure_core::Result { + self.pipeline.send(context, request).await + } +} + +/// Create a Pipeline from ServiceOptions +fn new_pipeline_from_options(options: ServiceOptions, credentials: IoTHubCredentials) -> Pipeline { + let auth_policy: Arc = Arc::new(AuthorizationPolicy::new(credentials)); + + // The `AuthorizationPolicy` must be the **last** retry policy. + // Policies can change the url and/or the headers, and the `AuthorizationPolicy` + // must be able to inspect them or the resulting token will be invalid. + let per_retry_policies = vec![ + Arc::new(options.timeout_policy) as Arc, + auth_policy, + ]; + + Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.options, + Vec::new(), + per_retry_policies, + ) +} + +/// Options to cufigure the ServiceClient +#[derive(Debug, Clone, Default)] +pub struct ServiceOptions { + options: ClientOptions, + timeout_policy: TimeoutPolicy, +} + +impl ServiceOptions { + /// set timeout duration for requests + pub fn set_timeout(&mut self, default_timeout: Timeout) { + self.timeout_policy = TimeoutPolicy::new(Some(default_timeout)) } } @@ -843,9 +897,8 @@ mod tests { fn from_connectionstring_success() -> 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 _ = ServiceClient::from_connection_string(http_client, connection_string, 3600)?; + let _ = ServiceClient::new_connection_string(connection_string, 3600)?; Ok(()) } @@ -854,14 +907,11 @@ mod tests { ) -> 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 _ = ServiceClient::from_connection_string(http_client.clone(), connection_string, 3600) - .is_err(); + let _ = ServiceClient::new_connection_string(connection_string, 3600).is_err(); let connection_string = "HostName=cool-iot-hub.azure-;SharedAccessKeyName=iot_hubowner;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg=="; - let _ = - ServiceClient::from_connection_string(http_client, connection_string, 3600).is_err(); + let _ = ServiceClient::new_connection_string(connection_string, 3600).is_err(); Ok(()) } @@ -869,9 +919,8 @@ mod tests { fn from_connectionstring_should_fail_on_empty_connection_string( ) -> Result<(), Box> { use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - let _ = ServiceClient::from_connection_string(http_client, "", 3600).is_err(); + let _ = ServiceClient::new_connection_string("", 3600).is_err(); Ok(()) } @@ -879,9 +928,7 @@ mod tests { fn from_connectionstring_should_fail_on_incomplete_connection_string( ) -> Result<(), Box> { use crate::service::ServiceClient; - let http_client = azure_core::new_http_client(); - - let _ = ServiceClient::from_connection_string(http_client, "HostName=cool-iot-hub.azure-devices.net;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg==", 3600).is_err(); + let _ = ServiceClient::new_connection_string( "HostName=cool-iot-hub.azure-devices.net;SharedAccessKey=YSB2ZXJ5IHNlY3VyZSBrZXkgaXMgaW1wb3J0YW50Cg==", 3600).is_err(); 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 index 2ca449ff45..70e279f9c6 100644 --- a/sdk/iot_hub/src/service/operations/apply_on_edge_device.rs +++ b/sdk/iot_hub/src/service/operations/apply_on_edge_device.rs @@ -15,7 +15,7 @@ operation! { impl ApplyOnEdgeDeviceBuilder { /// Performs the apply on edge device request - pub fn into_future(self) -> ApplyOnEdgeDevice { + pub fn into_future(mut self) -> ApplyOnEdgeDevice { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/devices/{}/applyConfigurationContent?api-version={}", @@ -32,10 +32,8 @@ impl ApplyOnEdgeDeviceBuilder { let body = azure_core::to_json(&body)?; request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await?; + self.client.send(&mut self.context, &mut request).await?; + Ok(()) }) } 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 index 0a039f584d..fe2ebdc945 100644 --- a/sdk/iot_hub/src/service/operations/create_or_update_configuration.rs +++ b/sdk/iot_hub/src/service/operations/create_or_update_configuration.rs @@ -2,7 +2,6 @@ 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; @@ -70,7 +69,7 @@ impl CreateOrUpdateConfigurationBuilder { } /// Performs the create or update request on the device identity - pub fn into_future(self) -> CreateOrUpdateConfiguration { + pub fn into_future(mut self) -> CreateOrUpdateConfiguration { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/configurations/{}?api-version={}", @@ -102,11 +101,9 @@ impl CreateOrUpdateConfigurationBuilder { let body = azure_core::to_json(&body)?; request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() + let response = self.client.send(&mut self.context, &mut request).await?; + + CreateOrUpdateConfigurationResponse::try_from(response).await }) } } 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 index e295b03f3c..007133d5b3 100644 --- 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 @@ -2,13 +2,12 @@ use crate::service::resources::{ identity::DesiredCapability, identity::IdentityOperation, AuthenticationMechanism, DeviceCapabilities, Status, }; -use crate::service::responses::DeviceIdentityResponse; +use crate::service::responses::CreateOrUpdateDeviceIdentityResponse; 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 @@ -38,7 +37,7 @@ impl CreateOrUpdateDeviceIdentityBuilder { } /// Performs the create or update request on the device identity - pub fn into_future(self) -> CreateOrUpdateDeviceIdentity { + pub fn into_future(mut self) -> CreateOrUpdateDeviceIdentity { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/devices/{}?api-version={}", @@ -67,17 +66,13 @@ impl CreateOrUpdateDeviceIdentityBuilder { let body = azure_core::to_json(&body)?; request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() + let response = self.client.send(&mut self.context, &mut request).await?; + + CreateOrUpdateDeviceIdentityResponse::try_from(response).await }) } } -pub type CreateOrUpdateDeviceIdentityResponse = DeviceIdentityResponse; - #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct CreateOrUpdateDeviceIdentityBody<'a> { 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 index 3d98496426..45f9e7df41 100644 --- 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 @@ -1,11 +1,10 @@ use crate::service::resources::{identity::IdentityOperation, AuthenticationMechanism}; -use crate::service::responses::ModuleIdentityResponse; +use crate::service::responses::CreateOrUpdateModuleIdentityResponse; 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 @@ -22,7 +21,7 @@ azure_core::operation! { impl CreateOrUpdateModuleIdentityBuilder { /// Performs the create or update request on the device identity - pub fn into_future(self) -> CreateOrUpdateModuleIdentity { + pub fn into_future(mut self) -> CreateOrUpdateModuleIdentity { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/devices/{}/modules/{}?api-version={}", @@ -51,17 +50,13 @@ impl CreateOrUpdateModuleIdentityBuilder { let body = azure_core::to_json(&body)?; request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() + let response = self.client.send(&mut self.context, &mut request).await?; + + CreateOrUpdateModuleIdentityResponse::try_from(response).await }) } } -pub type CreateOrUpdateModuleIdentityResponse = ModuleIdentityResponse; - #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct CreateOrUpdateModuleIdentityBody<'a, 'b, 'c> { diff --git a/sdk/iot_hub/src/service/operations/delete_configuration.rs b/sdk/iot_hub/src/service/operations/delete_configuration.rs index cb63d374a7..b5931f7743 100644 --- a/sdk/iot_hub/src/service/operations/delete_configuration.rs +++ b/sdk/iot_hub/src/service/operations/delete_configuration.rs @@ -13,7 +13,7 @@ azure_core::operation! { impl DeleteConfigurationBuilder { /// Execute the request to delete the configuration. - pub fn into_future(self) -> DeleteConfiguration { + pub fn into_future(mut self) -> DeleteConfiguration { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/configurations/{}?api-version={}", @@ -25,10 +25,8 @@ impl DeleteConfigurationBuilder { request.set_body(azure_core::EMPTY_BODY); - self.client - .http_client() - .execute_request_check_status(&request) - .await?; + self.client.send(&mut self.context, &mut request).await?; + Ok(()) }) } diff --git a/sdk/iot_hub/src/service/operations/delete_identity.rs b/sdk/iot_hub/src/service/operations/delete_identity.rs index 207e35c213..c268be6a0c 100644 --- a/sdk/iot_hub/src/service/operations/delete_identity.rs +++ b/sdk/iot_hub/src/service/operations/delete_identity.rs @@ -13,7 +13,7 @@ azure_core::operation! { impl DeleteIdentityBuilder { /// Execute the request to delete the module or device identity. - pub fn into_future(self) -> DeleteIdentity { + pub fn into_future(mut self) -> DeleteIdentity { Box::pin(async move { let uri = match &self.module_id { Some(module_id) => format!( @@ -31,10 +31,7 @@ impl DeleteIdentityBuilder { request.set_body(azure_core::EMPTY_BODY); - self.client - .http_client() - .execute_request_check_status(&request) - .await?; + self.client.send(&mut self.context, &mut request).await?; Ok(()) }) } diff --git a/sdk/iot_hub/src/service/operations/get_configuration.rs b/sdk/iot_hub/src/service/operations/get_configuration.rs index 139e57d53f..c5baf6bbef 100644 --- a/sdk/iot_hub/src/service/operations/get_configuration.rs +++ b/sdk/iot_hub/src/service/operations/get_configuration.rs @@ -1,3 +1,4 @@ +use crate::service::responses::ConfigurationResponse; use crate::service::{ServiceClient, API_VERSION}; use azure_core::Method; @@ -11,7 +12,7 @@ azure_core::operation! { impl GetConfigurationBuilder { /// Execute the request to get the configuration of a given identifier. - pub fn into_future(self) -> GetConfiguration { + pub fn into_future(mut self) -> GetConfiguration { Box::pin(async move { let uri = match self.configuration_id { Some(val) => format!( @@ -27,12 +28,11 @@ impl GetConfigurationBuilder { 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 + let response = self.client.send(&mut self.context, &mut request).await?; + + GetConfigurationResponse::try_from(response).await }) } } -pub type GetConfigurationResponse = crate::service::CollectedResponse; +pub type GetConfigurationResponse = ConfigurationResponse; diff --git a/sdk/iot_hub/src/service/operations/get_identity.rs b/sdk/iot_hub/src/service/operations/get_identity.rs index 8ab6d1207e..f4821e174d 100644 --- a/sdk/iot_hub/src/service/operations/get_identity.rs +++ b/sdk/iot_hub/src/service/operations/get_identity.rs @@ -1,4 +1,4 @@ -use crate::service::{ServiceClient, API_VERSION}; +use crate::service::{CollectedResponse, ServiceClient, API_VERSION}; use azure_core::Method; azure_core::operation! { @@ -11,7 +11,7 @@ azure_core::operation! { impl GetIdentityBuilder { /// Execute the request to get the identity of a device or module. - pub fn into_future(self) -> GetIdentity { + pub fn into_future(mut self) -> GetIdentity { Box::pin(async move { let uri = match self.module_id { Some(module_id) => format!( @@ -27,12 +27,11 @@ impl GetIdentityBuilder { 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 + let response = self.client.send(&mut self.context, &mut request).await?; + + GetIdentityResponse::from_response(response).await }) } } -pub type GetIdentityResponse = crate::service::CollectedResponse; +pub type GetIdentityResponse = CollectedResponse; diff --git a/sdk/iot_hub/src/service/operations/get_twin.rs b/sdk/iot_hub/src/service/operations/get_twin.rs index 8389ebb058..ebfeb9603a 100644 --- a/sdk/iot_hub/src/service/operations/get_twin.rs +++ b/sdk/iot_hub/src/service/operations/get_twin.rs @@ -11,7 +11,7 @@ azure_core::operation! { impl GetTwinBuilder { /// Execute the request to get the twin of a module or device. - pub fn into_future(self) -> GetTwin { + pub fn into_future(mut self) -> GetTwin { Box::pin(async move { let uri = match self.module_id { Some(val) => format!( @@ -27,10 +27,9 @@ impl GetTwinBuilder { 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 + let response = self.client.send(&mut self.context, &mut request).await?; + + GetTwinResponse::from_response(response).await }) } } diff --git a/sdk/iot_hub/src/service/operations/invoke_method.rs b/sdk/iot_hub/src/service/operations/invoke_method.rs index 868e6a6aa3..f7cbedd98c 100644 --- a/sdk/iot_hub/src/service/operations/invoke_method.rs +++ b/sdk/iot_hub/src/service/operations/invoke_method.rs @@ -2,7 +2,6 @@ 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 @@ -19,7 +18,7 @@ azure_core::operation! { impl InvokeMethodBuilder { /// Turn the builder into a `Future` - pub fn into_future(self) -> InvokeMethod { + pub fn into_future(mut self) -> InvokeMethod { Box::pin(async move { let uri = match &self.module_id { Some(module_id_value) => format!( @@ -44,11 +43,9 @@ impl InvokeMethodBuilder { request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await? - .try_into() + let response = self.client.send(&mut self.context, &mut request).await?; + + InvokeMethodResponse::try_from(response).await }) } } diff --git a/sdk/iot_hub/src/service/operations/query.rs b/sdk/iot_hub/src/service/operations/query.rs index d83478d8e0..2dcc46848f 100644 --- a/sdk/iot_hub/src/service/operations/query.rs +++ b/sdk/iot_hub/src/service/operations/query.rs @@ -4,7 +4,6 @@ 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)] @@ -23,7 +22,7 @@ azure_core::operation! { impl QueryBuilder { /// Invoke a qiven query on the IoT Hub - pub fn into_future(self) -> Query { + pub fn into_future(mut self) -> Query { Box::pin(async move { let uri = format!( "https://{}.azure-devices.net/devices/query?api-version={}", @@ -38,11 +37,9 @@ impl QueryBuilder { 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() + let response = self.client.send(&mut self.context, &mut request).await?; + + QueryResponse::try_from(response).await }) } } 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 index f5538875fe..25dfccf80b 100644 --- a/sdk/iot_hub/src/service/operations/update_or_replace_twin.rs +++ b/sdk/iot_hub/src/service/operations/update_or_replace_twin.rs @@ -28,9 +28,8 @@ impl UpdateOrReplaceTwinBuilder { /// ``` /// # 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 iot_hub = ServiceClient::new_connection_string(connection_string, 3600).expect("Failed to create the ServiceClient!"); /// let twin = iot_hub.update_device_twin("some-device") /// .tag("TagName", "TagValue") /// .tag("AnotherTag", "WithAnotherValue") @@ -51,14 +50,13 @@ impl UpdateOrReplaceTwinBuilder { /// 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 iot_hub = ServiceClient::new_connection_string(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 { + pub fn into_future(mut self) -> UpdateOrReplaceTwin { Box::pin(async move { let body = DesiredTwinBody { tags: self.desired_tags.unwrap_or_default(), @@ -86,10 +84,9 @@ impl UpdateOrReplaceTwinBuilder { request.set_body(body); - self.client - .http_client() - .execute_request_check_status(&request) - .await + let response = self.client.send(&mut self.context, &mut request).await?; + + UpdateOrReplaceTwinResponse::from_response(response).await }) } } diff --git a/sdk/iot_hub/src/service/responses/configuration_response.rs b/sdk/iot_hub/src/service/responses/configuration_response.rs index bb5351b922..9cb2f988ec 100644 --- a/sdk/iot_hub/src/service/responses/configuration_response.rs +++ b/sdk/iot_hub/src/service/responses/configuration_response.rs @@ -1,5 +1,5 @@ use crate::service::resources::Configuration; -use azure_core::error::Error; +use azure_core::{error::Error, CollectedResponse}; use serde::{Deserialize, Serialize}; /// The configuration response @@ -9,15 +9,11 @@ pub type ConfigurationResponse = Configuration; #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct MultipleConfigurationResponse(Vec); -impl std::convert::TryFrom for ConfigurationResponse { - type Error = Error; - - fn try_from(response: crate::service::CollectedResponse) -> azure_core::Result { - let body = response.body(); - - let configuration_response: ConfigurationResponse = serde_json::from_slice(body)?; - - Ok(configuration_response) +impl ConfigurationResponse { + pub(crate) async fn try_from(response: azure_core::Response) -> azure_core::Result { + let collected = CollectedResponse::from_response(response).await?; + let body = collected.body(); + Ok(serde_json::from_slice(body)?) } } diff --git a/sdk/iot_hub/src/service/responses/device_identity_response.rs b/sdk/iot_hub/src/service/responses/device_identity_response.rs index 93be03c908..63c5465b37 100644 --- a/sdk/iot_hub/src/service/responses/device_identity_response.rs +++ b/sdk/iot_hub/src/service/responses/device_identity_response.rs @@ -48,3 +48,14 @@ impl std::convert::TryFrom for DeviceIdentity Ok(device_identity_response) } } + +/// Response of CreateOrUpdateDeviceIdentity +pub type CreateOrUpdateDeviceIdentityResponse = DeviceIdentityResponse; + +impl CreateOrUpdateDeviceIdentityResponse { + pub(crate) async fn try_from(response: azure_core::Response) -> azure_core::Result { + let collected = azure_core::CollectedResponse::from_response(response).await?; + let body = collected.body(); + Ok(serde_json::from_slice(body)?) + } +} diff --git a/sdk/iot_hub/src/service/responses/invoke_method_response.rs b/sdk/iot_hub/src/service/responses/invoke_method_response.rs index 9f8e95bf96..271dbe1f7d 100644 --- a/sdk/iot_hub/src/service/responses/invoke_method_response.rs +++ b/sdk/iot_hub/src/service/responses/invoke_method_response.rs @@ -1,4 +1,3 @@ -use azure_core::error::Error; use serde::Deserialize; /// The DirectMethodResponse struct contains the response @@ -11,14 +10,10 @@ pub struct InvokeMethodResponse { pub payload: Option, } -impl std::convert::TryFrom for InvokeMethodResponse { - type Error = Error; - - fn try_from(response: crate::service::CollectedResponse) -> azure_core::Result { - let body = response.body(); - - let invoke_method_response: InvokeMethodResponse = serde_json::from_slice(body)?; - - Ok(invoke_method_response) +impl InvokeMethodResponse { + pub(crate) async fn try_from(response: azure_core::Response) -> azure_core::Result { + let collected = azure_core::CollectedResponse::from_response(response).await?; + let body = collected.body(); + Ok(serde_json::from_slice(body)?) } } diff --git a/sdk/iot_hub/src/service/responses/mod.rs b/sdk/iot_hub/src/service/responses/mod.rs index 5bb6aac84b..c2f898c98b 100644 --- a/sdk/iot_hub/src/service/responses/mod.rs +++ b/sdk/iot_hub/src/service/responses/mod.rs @@ -7,9 +7,9 @@ mod module_twin_response; mod query_response; pub use configuration_response::{ConfigurationResponse, MultipleConfigurationResponse}; -pub use device_identity_response::DeviceIdentityResponse; +pub use device_identity_response::{CreateOrUpdateDeviceIdentityResponse, DeviceIdentityResponse}; pub use device_twin_response::DeviceTwinResponse; pub use invoke_method_response::InvokeMethodResponse; -pub use module_identity_response::ModuleIdentityResponse; +pub use module_identity_response::{CreateOrUpdateModuleIdentityResponse, ModuleIdentityResponse}; pub use module_twin_response::ModuleTwinResponse; pub use query_response::QueryResponse; diff --git a/sdk/iot_hub/src/service/responses/module_identity_response.rs b/sdk/iot_hub/src/service/responses/module_identity_response.rs index 067d8f46ca..ed5a374a33 100644 --- a/sdk/iot_hub/src/service/responses/module_identity_response.rs +++ b/sdk/iot_hub/src/service/responses/module_identity_response.rs @@ -40,3 +40,14 @@ impl std::convert::TryFrom for ModuleIdentity Ok(module_identity_response) } } + +/// Response for CreateOrUpdateModuleIdentity +pub type CreateOrUpdateModuleIdentityResponse = ModuleIdentityResponse; + +impl CreateOrUpdateModuleIdentityResponse { + pub(crate) async fn try_from(response: azure_core::Response) -> azure_core::Result { + let collected = azure_core::CollectedResponse::from_response(response).await?; + let body = collected.body(); + Ok(serde_json::from_slice(body)?) + } +} diff --git a/sdk/iot_hub/src/service/responses/query_response.rs b/sdk/iot_hub/src/service/responses/query_response.rs index 2655ff4189..367bd99c38 100644 --- a/sdk/iot_hub/src/service/responses/query_response.rs +++ b/sdk/iot_hub/src/service/responses/query_response.rs @@ -1,4 +1,3 @@ -use azure_core::error::Error; use azure_core::headers::{self, continuation_token_from_headers_optional}; use azure_core::prelude::Continuation; use serde_json::Value; @@ -13,17 +12,15 @@ pub struct QueryResponse { pub item_type: String, } -impl std::convert::TryFrom for QueryResponse { - type Error = Error; - - fn try_from(response: crate::service::CollectedResponse) -> azure_core::Result { - let headers = response.headers(); - let body: &[u8] = response.body(); +impl QueryResponse { + pub(crate) async fn try_from(response: azure_core::Response) -> azure_core::Result { + let collected = azure_core::CollectedResponse::from_response(response).await?; + let body = collected.body(); Ok(QueryResponse { result: serde_json::from_slice(body)?, - continuation_token: continuation_token_from_headers_optional(headers)?, - item_type: headers.get_as(&headers::ITEM_TYPE)?, + continuation_token: continuation_token_from_headers_optional(collected.headers())?, + item_type: collected.headers().get_as(&headers::ITEM_TYPE)?, }) } } diff --git a/sdk/storage/src/core/clients/storage_client.rs b/sdk/storage/src/core/clients/storage_client.rs index fbb9685c0d..342153c873 100644 --- a/sdk/storage/src/core/clients/storage_client.rs +++ b/sdk/storage/src/core/clients/storage_client.rs @@ -4,14 +4,13 @@ use crate::shared_access_signature::account_sas::{ AccountSasPermissions, AccountSasResource, AccountSasResourceType, AccountSharedAccessSignature, }; use crate::ConnectionString; -use crate::TimeoutPolicy; use azure_core::date; use azure_core::{ auth::TokenCredential, error::{Error, ErrorKind, ResultExt}, headers::*, prelude::Timeout, - Body, ClientOptions, Context, Method, Pipeline, Request, Response, + Body, ClientOptions, Context, Method, Pipeline, Request, Response, TimeoutPolicy, }; use std::sync::Arc; use time::OffsetDateTime; @@ -514,7 +513,7 @@ fn get_endpoint_uri( }) } -/// Create a Pipeline from CosmosOptions +/// Create a Pipeline from StorageOptions fn new_pipeline_from_options(options: StorageOptions, credentials: StorageCredentials) -> Pipeline { let auth_policy: Arc = Arc::new(AuthorizationPolicy::new(credentials)); diff --git a/sdk/storage/src/core/mod.rs b/sdk/storage/src/core/mod.rs index 7fcf81c658..3c1bace130 100644 --- a/sdk/storage/src/core/mod.rs +++ b/sdk/storage/src/core/mod.rs @@ -7,7 +7,6 @@ pub mod hmac; mod macros; pub mod prelude; pub mod shared_access_signature; -mod timeout_policy; pub use self::connection_string::{ConnectionString, EndpointProtocol}; pub use self::connection_string_builder::ConnectionStringBuilder; @@ -19,7 +18,6 @@ pub mod storage_shared_key_credential; mod stored_access_policy; pub use azure_core::error::{Error, ErrorKind, ResultExt}; pub mod xml; -pub use timeout_policy::TimeoutPolicy; #[derive(Debug, Clone, PartialEq)] pub struct IPRange {