#![allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
use std::time::{Duration, Instant};
use zerodds_dcps::runtime::{DcpsRuntime, RuntimeConfig, UserReaderConfig, UserWriterConfig};
use zerodds_qos::{
DeadlineQosPolicy, DurabilityKind, LifespanQosPolicy, LivelinessQosPolicy, OwnershipKind,
};
use zerodds_rtps::wire_types::{GuidPrefix, Locator};
fn writer_cfg(topic: &str) -> UserWriterConfig {
UserWriterConfig {
topic_name: topic.into(),
type_name: "RawBytes".into(),
reliable: true,
durability: DurabilityKind::Volatile,
deadline: DeadlineQosPolicy::default(),
lifespan: LifespanQosPolicy::default(),
liveliness: LivelinessQosPolicy::default(),
ownership: OwnershipKind::Shared,
ownership_strength: 0,
partition: vec![],
user_data: vec![],
topic_data: vec![],
group_data: vec![],
type_identifier: zerodds_types::TypeIdentifier::None,
data_representation_offer: None,
}
}
fn reader_cfg(topic: &str) -> UserReaderConfig {
UserReaderConfig {
topic_name: topic.into(),
type_name: "RawBytes".into(),
reliable: true,
durability: DurabilityKind::Volatile,
deadline: DeadlineQosPolicy::default(),
liveliness: LivelinessQosPolicy::default(),
ownership: OwnershipKind::Shared,
partition: vec![],
user_data: vec![],
group_data: vec![],
topic_data: vec![],
type_identifier: zerodds_types::TypeIdentifier::None,
type_consistency: zerodds_types::qos::TypeConsistencyEnforcement::default(),
data_representation_offer: None,
}
}
fn client_cfg(server: &Locator) -> RuntimeConfig {
let loopback = Locator::udp_v4([127, 0, 0, 1], server.port);
RuntimeConfig {
spdp_multicast_send: false,
initial_peers: vec![loopback],
..RuntimeConfig::default()
}
}
#[cfg_attr(target_os = "macos", ignore)]
#[test]
fn clients_discover_each_other_through_the_server() {
let domain = 95;
let host = [0x71u8; 4];
let mk = |tag: u8| {
let mut p = [tag; 12];
p[..4].copy_from_slice(&host);
GuidPrefix::from_bytes(p)
};
let server = DcpsRuntime::start(domain, mk(0x51), RuntimeConfig::discovery_server()).unwrap();
let server_loc = server.spdp_unicast_locator();
let a = DcpsRuntime::start(domain, mk(0xA1), client_cfg(&server_loc)).unwrap();
let b = DcpsRuntime::start(domain, mk(0xB2), client_cfg(&server_loc)).unwrap();
let b_prefix = b.guid_prefix;
let deadline = Instant::now() + Duration::from_secs(20);
let mut found = false;
while Instant::now() < deadline {
if a.discovered_participants()
.iter()
.any(|dp| dp.sender_prefix == b_prefix)
{
found = true;
break;
}
std::thread::sleep(Duration::from_millis(50));
}
assert!(
found,
"client A never discovered client B through the discovery server (relay broken)"
);
let a_prefix = a.guid_prefix;
let mut found_back = false;
while Instant::now() < deadline {
if b.discovered_participants()
.iter()
.any(|dp| dp.sender_prefix == a_prefix)
{
found_back = true;
break;
}
std::thread::sleep(Duration::from_millis(50));
}
assert!(
found_back,
"client B never discovered client A through the server"
);
let topic = "A1DiscServer";
let w = a.register_user_writer(writer_cfg(topic)).unwrap();
let (r, rx) = b.register_user_reader(reader_cfg(topic)).unwrap();
let mdl = Instant::now() + Duration::from_secs(15);
while Instant::now() < mdl
&& (b.user_reader_matched_count(r) < 1 || a.user_writer_matched_count(w) < 1)
{
std::thread::sleep(Duration::from_millis(20));
}
assert!(
b.user_reader_matched_count(r) >= 1 && a.user_writer_matched_count(w) >= 1,
"A<->B did not match directly via SEDP after discovery-server bridging"
);
a.write_user_sample(w, vec![0xA1, 0x5E, 0x12, 0x34])
.expect("write");
let got = rx.recv_timeout(Duration::from_secs(3));
assert!(
got.is_ok(),
"user data did not flow A->B after discovery-server bridging"
);
}