Skip to content

Commit

Permalink
[eclipse-uprotocol#122] Make CallOptions immutable
Browse files Browse the repository at this point in the history
Changed CallOptions struct to only support setting fields by means
of constructors, effectively making it immutable. This way
we will have better control over which fields may or may not be set
for the different types of messages to use the CallOptions for.

Also removed the traceparent field because it should not be necessary
to explicitly set it. Instead, when a UMessage is created, the current
span will be looked up in the current thread/future context.
  • Loading branch information
sophokles73 committed Jul 4, 2024
1 parent 7148f78 commit a0cdb95
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 107 deletions.
104 changes: 17 additions & 87 deletions src/communication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,45 +60,42 @@ impl Display for RegistrationError {

impl Error for RegistrationError {}

const DEFAULT_TTL: u32 = 10_000; // 10 seconds

/// General options that clients might want to specify when sending a uProtocol message.
#[derive(Debug)]
pub struct CallOptions {
ttl: u32,
message_id: Option<UUID>,
token: Option<String>,
priority: Option<UPriority>,
traceparent: Option<String>,
}

impl Default for CallOptions {
/// Creates empty options with a TTL of 10s.
fn default() -> Self {
CallOptions {
ttl: DEFAULT_TTL,
message_id: None,
token: None,
priority: None,
traceparent: None,
}
}
}

impl CallOptions {
/// Creates new call options.
/// Creates new call options for an RPC Request.
///
/// # Arguments
///
/// * `ttl` - The message's time-to-live in milliseconds.
/// * `message_id` - The identifier to use for the message or `None` to use a generated identifier.
/// * `token` - The token to use for authenticating to infrastructure and service endpoints.
/// * `priority` - The message's priority or `None` to use the default priority.
/// * `priority` - The message's priority or `None` to use the default priority for RPC Requests.
///
/// # Returns
///
/// `CallOption` with specified ttl value, token and priority parameters.
pub fn new(
/// Options suitable for invoking an RPC method.
///
/// # Examples
///
/// ```rust
/// use up_rust::{UPriority, UUID, communication::CallOptions};
///
/// let uuid = UUID::new();
/// let options = CallOptions::for_rpc_request(15_000, Some(uuid.clone()), Some("token".to_string()), Some(UPriority::UPRIORITY_CS2));
/// assert_eq!(options.ttl(), 15_000);
/// assert_eq!(options.message_id(), Some(uuid));
/// assert_eq!(options.token(), Some("token".to_string()));
/// assert_eq!(options.priority(), Some(UPriority::UPRIORITY_CS2));
/// ```
pub fn for_rpc_request(
ttl: u32,
message_id: Option<UUID>,
token: Option<String>,
Expand All @@ -109,95 +106,28 @@ impl CallOptions {
message_id,
token,
priority,
traceparent: None,
}
}

/// Sets the message's time-to-live.
///
/// # Arguments
///
/// * `ttl` - The time-to-live in milliseconds.
///
/// # Returns
///
/// `CallOption` with specified ttl value.
pub fn with_ttl(&mut self, ttl: u32) -> &mut Self {
self.ttl = ttl;
self
}

/// Gets the message's time-to-live in milliseconds.
pub fn ttl(&self) -> u32 {
self.ttl
}

/// Sets the identifier to use for the message.
///
/// # Returns
///
/// `CallOption` with specified reqid value.
pub fn with_message_id(&mut self, message_id: UUID) -> &mut Self {
self.message_id = Some(message_id);
self
}

/// Gets the identifier to use for the message.
pub fn message_id(&self) -> Option<UUID> {
self.message_id.clone()
}

/// Sets the token to use for authenticating to infrastructure and service endpoints.
///
/// # Returns
///
/// `CallOption` with specified token value.
pub fn with_token<T: Into<String>>(&mut self, token: T) -> &mut Self {
self.token = Some(token.into());
self
}

/// Gets the token to use for authenticating to infrastructure and service endpoints.
pub fn token(&self) -> Option<String> {
self.token.clone()
}

/// Sets the message's priority.
///
/// If not set explicitly, the default priority for RPC calls will be used.
///
/// # Returns
///
/// `CallOption` with specified priority value.
pub fn with_priority(&mut self, priority: UPriority) -> &mut Self {
self.priority = Some(priority);
self
}

/// Gets the message's priority.
pub fn priority(&self) -> Option<UPriority> {
self.priority
}

/// Sets the W3C Trace Context that the message is part of.
///
/// # Arguments
///
/// * `traceparent` - The [traceparent](https://w3c.github.io/trace-context/#traceparent-header) value identifying the trace context.
///
/// # Returns
///
/// `CallOption` with specified priority value.
pub fn with_traceparent<T: Into<String>>(&mut self, traceparent: T) -> &mut Self {
self.traceparent = Some(traceparent.into());
self
}

/// Gets the [traceparent](https://w3c.github.io/trace-context/#traceparent-header) value identifying the trace context that
/// the message is part of.
pub fn traceparent(&self) -> Option<String> {
self.traceparent.clone()
}
}

/// A wrapper around (raw) message payload data and the corresponding payload format.
Expand Down
32 changes: 12 additions & 20 deletions src/communication/in_memory_rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,6 @@ impl RpcClient for InMemoryRpcClient {
if let Some(priority) = call_options.priority() {
builder.with_priority(priority);
}
if let Some(traceparent) = call_options.traceparent() {
builder.with_traceparent(traceparent);
}
let rpc_request_message = if let Some(pl) = payload {
let format = pl.payload_format();
builder.build_with_payload(pl.payload(), format)
Expand Down Expand Up @@ -348,8 +345,8 @@ mod tests {

// WHEN invoking a remote service operation
let message_id = UUID::build();
let mut call_options = CallOptions::default();
call_options.with_message_id(message_id.clone());
let call_options =
CallOptions::for_rpc_request(5_000, Some(message_id.clone()), None, None);
let response = client
.invoke_method(service_method_uri(), call_options, None)
.await;
Expand All @@ -362,14 +359,12 @@ mod tests {
#[tokio::test]
async fn test_invoke_method_succeeds() {
let message_id = UUID::build();
let traceparent = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
let mut call_options = CallOptions::default();
call_options
.with_message_id(message_id.clone())
.with_priority(crate::UPriority::UPRIORITY_CS6)
.with_ttl(5_000)
.with_token("my_token")
.with_traceparent(traceparent);
let call_options = CallOptions::for_rpc_request(
5_000,
Some(message_id.clone()),
Some("my_token".to_string()),
Some(crate::UPriority::UPRIORITY_CS6),
);

// GIVEN an RPC client
let listener_ref: Arc<Mutex<Option<Arc<dyn UListener>>>> = Arc::new(Mutex::new(None));
Expand All @@ -395,7 +390,6 @@ mod tests {
&& attribs.priority.value() == UPriority::UPRIORITY_CS6.value()
&& attribs.ttl == Some(5_000)
&& attribs.token == Some("my_token".to_string())
&& attribs.traceparent == Some(traceparent.to_string())
})
})
.returning(move |request_message| {
Expand Down Expand Up @@ -472,10 +466,10 @@ mod tests {

// WHEN invoking the remote service operation
let message_id = UUID::build();
let mut call_options = CallOptions::default();
call_options.with_message_id(message_id.clone());
let call_options =
CallOptions::for_rpc_request(5_000, Some(message_id.clone()), None, None);
let response = client
.invoke_method(service_method_uri(), CallOptions::default(), None)
.invoke_method(service_method_uri(), call_options, None)
.await;

// THEN the invocation has failed with the error returned from the service
Expand All @@ -501,9 +495,7 @@ mod tests {

// WHEN invoking the remote service operation
let message_id = UUID::build();
let mut call_options = CallOptions::default();
call_options.with_ttl(20);
call_options.with_message_id(message_id.clone());
let call_options = CallOptions::for_rpc_request(20, Some(message_id.clone()), None, None);
let response = client
.invoke_method(service_method_uri(), call_options, None)
.await;
Expand Down

0 comments on commit a0cdb95

Please sign in to comment.