in rust/azure_iot_operations_protocol/src/rpc_command/invoker.rs [186:272]
fn from(value: RemoteError) -> Self {
// NOTE: We do not use the AIOProtocolError constructor functions, as they would
// result in additional allocations (String -> &str -> String). Because there is no
// Default implementation for AIOProtocolError (nor can there be), we will initialize a
// "default" instance here, and update fields as necessary.
let remote_error_clone = value.clone();
let mut aio_error = AIOProtocolError {
kind: AIOProtocolErrorKind::UnknownError,
message: value.status_message,
is_shallow: false, // Always false because a RemoteError implies network activity
is_remote: true, // Always true because it is a RemoteError
nested_error: Some(Box::new(remote_error_clone)),
header_name: None,
header_value: None,
timeout_name: None,
timeout_value: None,
property_name: None,
property_value: None,
command_name: None, // Will need to update this after return
protocol_version: Some(value.protocol_version.to_string()),
supported_protocol_major_versions: value.supported_protocol_major_versions,
};
match value.status_code {
StatusCode::Ok | StatusCode::NoContent => {
// NOTE: Could remove this by defining a subset of the StatusCode enums
// e.g. FailureStatusCode, but that might be overkill
unreachable!("Invalid status code for RemoteError")
}
StatusCode::BadRequest => {
if value.invalid_property_name.is_some() && value.invalid_property_value.is_some() {
aio_error.kind = AIOProtocolErrorKind::HeaderInvalid;
aio_error.header_name = value.invalid_property_name;
aio_error.header_value = value.invalid_property_value;
} else if value.invalid_property_name.is_some() {
aio_error.kind = AIOProtocolErrorKind::HeaderMissing;
aio_error.header_name = value.invalid_property_name;
} else {
aio_error.kind = AIOProtocolErrorKind::PayloadInvalid;
}
}
StatusCode::RequestTimeout => {
aio_error.kind = AIOProtocolErrorKind::Timeout;
aio_error.timeout_name = value.invalid_property_name;
aio_error.timeout_value = value.invalid_property_value.and_then(|timeout_s| {
match timeout_s.parse::<iso8601_duration::Duration>() {
Ok(d) => d.to_std(),
Err(_) => None,
}
});
}
StatusCode::UnsupportedMediaType => {
aio_error.kind = AIOProtocolErrorKind::HeaderInvalid;
aio_error.header_name = value.invalid_property_name;
aio_error.header_value = value.invalid_property_value;
}
StatusCode::InternalServerError => {
// TODO: We may want to narrow this logic a bit to cover only valid cases.
// but for now, this is the same logic from prior iterations. When revisiting
// errors, this may be able to be cleaned up more.
if value.is_application_error {
aio_error.kind = AIOProtocolErrorKind::ExecutionException;
aio_error.property_name = value.invalid_property_name;
aio_error.property_value = value.invalid_property_value.map(Value::String);
} else if value.invalid_property_name.is_some() {
aio_error.kind = AIOProtocolErrorKind::InternalLogicError;
aio_error.property_name = value.invalid_property_name;
aio_error.property_value = value.invalid_property_value.map(Value::String);
} else {
aio_error.kind = AIOProtocolErrorKind::UnknownError;
// It is expected that value.invalid_property_name and
// value.invalid_property_value are None, but they are not set
// in order to ensure a None value.
// Not sure that this is entirely desirable.
}
}
StatusCode::ServiceUnavailable => {
aio_error.kind = AIOProtocolErrorKind::StateInvalid;
aio_error.property_name = value.invalid_property_name;
aio_error.property_value = value.invalid_property_value.map(Value::String);
}
StatusCode::VersionNotSupported => {
aio_error.kind = AIOProtocolErrorKind::UnsupportedVersion;
}
}
aio_error
}