Skip to content

Commit 0bceeb2

Browse files
catappreciationhours2PLeVasseursophokles73vidishac2004
authored
Added a conversion function from UUri to iceorxy2 ServiceNames
Co-authored-by: Pete LeVasseur <plevasseur@gmail.com> Co-authored-by: Kai Hudalla <sophokles.kh@gmail.com> Co-authored-by: vidishac2004 <144144085+vidishac2004@users.noreply.github.com>
1 parent 5ebc776 commit 0bceeb2

3 files changed

Lines changed: 183 additions & 2 deletions

File tree

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# up-transport-iceoryx2-rust
2-
Rust uTransport implementation for iceoryx2
2+
Rust uTransport implementation for iceoryx2

src/lib.rs

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
use async_trait::async_trait;
22
use std::sync::Arc;
3-
use up_rust::{UListener, UMessage, UStatus, UTransport, UUri};
3+
use up_rust::{UCode, UListener, UMessage, UStatus, UTransport, UUri};
44

55
/// This will be the main struct for our uProtocol transport.
66
/// It will hold the state necessary to communicate with iceoryx2,
77
/// such as the service connection and active listeners.
88
pub struct Iceoryx2Transport {}
99

10+
enum MessageType {
11+
RpcRequest,
12+
RpcResponseOrNotification,
13+
Publish,
14+
}
15+
1016
// The #[async_trait] attribute enables async functions in our trait impl.
1117
#[async_trait]
1218
impl UTransport for Iceoryx2Transport {
@@ -33,7 +39,181 @@ impl UTransport for Iceoryx2Transport {
3339
}
3440
}
3541

42+
#[allow(dead_code)]
43+
impl Iceoryx2Transport {
44+
fn encode_uuri_segments(uuri: &UUri) -> Vec<String> {
45+
vec![
46+
uuri.authority_name.clone(),
47+
Self::encode_hex(uuri.uentity_type_id() as u32),
48+
Self::encode_hex(uuri.uentity_instance_id() as u32),
49+
Self::encode_hex(uuri.uentity_major_version() as u32),
50+
Self::encode_hex(uuri.resource_id() as u32),
51+
]
52+
}
53+
54+
fn encode_hex(value: u32) -> String {
55+
format!("{:X}", value)
56+
}
57+
58+
/// Assumption: valid source and sink URIs provided:
59+
/// send() makes use of UAttributesValidator
60+
/// register_listener() and unregister_listener() use verify_filter_criteria()
61+
/// Criteria for identification of message types can be found here: https://github.com/eclipse-uprotocol/up-spec/blob/main/basics/uattributes.adoc
62+
fn determine_message_type(source: &UUri, sink: Option<&UUri>) -> Result<MessageType, UStatus> {
63+
let src_id = source.resource_id;
64+
let sink_id = sink.map(|s| s.resource_id);
65+
66+
if src_id == 0 {
67+
if let Some(id) = sink_id {
68+
if id >= 1 && id <= 0x7FFF {
69+
return Ok(MessageType::RpcRequest);
70+
}
71+
}
72+
} else if sink_id == Some(0) && src_id >= 1 && src_id <= 0xFFFE {
73+
return Ok(MessageType::RpcResponseOrNotification);
74+
} else if src_id >= 1 && src_id <= 0x7FFF {
75+
return Ok(MessageType::Publish);
76+
}
77+
78+
Err(UStatus::fail_with_code(
79+
UCode::INVALID_ARGUMENT,
80+
"Unsupported UMessageType",
81+
))
82+
}
83+
84+
/// Called in send(), register_listener() and unregister_listener()
85+
fn compute_service_name(source: &UUri, sink: Option<&UUri>) -> Result<String, UStatus> {
86+
let join_segments = |segments: Vec<String>| segments.join("/");
87+
88+
match Self::determine_message_type(source, sink)? {
89+
MessageType::RpcRequest => {
90+
let Some(sink_uri) = sink else {
91+
return Err(UStatus::fail_with_code(
92+
UCode::INVALID_ARGUMENT,
93+
"sink required for RpcRequest",
94+
));
95+
};
96+
let segments = Self::encode_uuri_segments(sink_uri);
97+
Ok(format!("up/{}", join_segments(segments)))
98+
}
99+
MessageType::RpcResponseOrNotification => {
100+
let Some(sink_uri) = sink else {
101+
return Err(UStatus::fail_with_code(
102+
UCode::INVALID_ARGUMENT,
103+
"sink required for ResponseOrNotification",
104+
));
105+
};
106+
let source_segments = Self::encode_uuri_segments(source);
107+
let sink_segments = Self::encode_uuri_segments(sink_uri);
108+
Ok(format!(
109+
"up/{}/{}",
110+
join_segments(source_segments),
111+
join_segments(sink_segments)
112+
))
113+
}
114+
MessageType::Publish => {
115+
let segments = Self::encode_uuri_segments(source);
116+
Ok(format!("up/{}", join_segments(segments)))
117+
}
118+
}
119+
}
120+
}
121+
36122
#[cfg(test)]
37123
mod tests {
38124
use super::*;
125+
126+
fn test_uri(authority: &str, instance: u16, typ: u16, version: u8, resource: u16) -> UUri {
127+
let entity_id = ((instance as u32) << 16) | (typ as u32);
128+
UUri::try_from_parts(authority, entity_id, version, resource).unwrap()
129+
}
130+
131+
// performing successful tests for service name computation
132+
133+
#[test]
134+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
135+
fn test_publish_service_name() {
136+
let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x7FFF);
137+
138+
let name = Iceoryx2Transport::compute_service_name(&source, None).unwrap();
139+
assert_eq!(name, "up/device1/10AB/0/3/7FFF");
140+
}
141+
142+
#[test]
143+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
144+
fn test_notification_service_name() {
145+
let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x80CD);
146+
let sink = test_uri("device1", 0x0000, 0x30EF, 0x04, 0x0000);
147+
let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap();
148+
assert_eq!(name, "up/device1/10AB/0/3/80CD/device1/30EF/0/4/0");
149+
}
150+
151+
#[test]
152+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
153+
fn test_rpc_request_service_name() {
154+
let sink = test_uri("device1", 0x0004, 0x03AB, 0x03, 0x0000);
155+
let reply_to = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB);
156+
157+
let name = Iceoryx2Transport::compute_service_name(&sink, Some(&reply_to)).unwrap();
158+
assert_eq!(name, "up/device1/CD/0/4/B");
159+
}
160+
161+
#[test]
162+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
163+
fn test_rpc_response_service_name() {
164+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB);
165+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000);
166+
167+
let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap();
168+
assert_eq!(name, "up/device1/CD/0/4/B/device1/3AB/4/3/0");
169+
}
170+
171+
// performing failing tests for service name computation
172+
173+
#[test]
174+
// .specitem[dsn~up-attributes-request-source~1]
175+
// .specitem[dsn~up-attributes-response-source~1]
176+
// .specitem[dsn~up-attributes-notification-source~1]
177+
fn test_missing_uri_error() {
178+
let uuri = UUri::new();
179+
let result = Iceoryx2Transport::compute_service_name(&uuri, None);
180+
181+
assert!(result.is_err());
182+
assert_eq!(result.unwrap_err().get_code(), UCode::INVALID_ARGUMENT);
183+
}
184+
185+
#[test]
186+
//both source and sink have resource ID equal to 0
187+
// .specitem[dsn~up-attributes-request-source~1]
188+
// .specitem[dsn~up-attributes-request-sink~1]
189+
// .specitem[dsn~up-attributes-response-source~1]
190+
// .specitem[dsn~up-attributes-response-sink~1]
191+
fn test_fail_resource_id_error() {
192+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000);
193+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000);
194+
let result = Iceoryx2Transport::compute_service_name(&source, Some(&sink));
195+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
196+
}
197+
198+
#[test]
199+
//source has resource id=0 but missing sink
200+
// .specitem[dsn~up-attributes-request-sink~1]
201+
// .specitem[dsn~up-attributes-request-source~1]
202+
fn test_fail_missing_sink_error() {
203+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000);
204+
let result = Iceoryx2Transport::compute_service_name(&source, None);
205+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
206+
}
207+
208+
#[test]
209+
//missing source URI
210+
// .specitem[dsn~up-attributes-request-source~1]
211+
// .specitem[dsn~up-attributes-response-source~1]
212+
// .specitem[dsn~up-attributes-notification-source~1]
213+
fn test_fail_missing_source_error() {
214+
let uuri = UUri::new();
215+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x000);
216+
let result = Iceoryx2Transport::compute_service_name(&uuri, Some(&sink));
217+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
218+
}
39219
}

0 commit comments

Comments
 (0)