From cee3019e68711aa9bd60b6fe118dee4ce9ba0aa1 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Thu, 5 Sep 2024 10:36:22 +0200 Subject: [PATCH 1/2] [#370] Introduce domains example --- examples/Cargo.toml | 17 +++++ examples/README.md | 1 + examples/rust/domains/README.md | 24 +++++++ examples/rust/domains/discovery.rs | 61 ++++++++++++++++ examples/rust/domains/publisher.rs | 104 ++++++++++++++++++++++++++++ examples/rust/domains/subscriber.rs | 91 ++++++++++++++++++++++++ 6 files changed, 298 insertions(+) create mode 100644 examples/rust/domains/README.md create mode 100644 examples/rust/domains/discovery.rs create mode 100644 examples/rust/domains/publisher.rs create mode 100644 examples/rust/domains/subscriber.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 826a21171..462bbc138 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -13,6 +13,9 @@ version = { workspace = true } [dependencies] iceoryx2 = { workspace = true } iceoryx2-bb-container = { workspace = true } +iceoryx2-bb-log = { workspace = true } +iceoryx2-bb-system-types = { workspace = true } +clap = { workspace = true } [lib] name = "examples_common" @@ -83,3 +86,17 @@ path = "rust/service_attributes/opener.rs" [[example]] name = "service_attributes_incompatible" path = "rust/service_attributes/incompatible.rs" + +# domains + +[[example]] +name = "domains_publisher" +path = "rust/domains/publisher.rs" + +[[example]] +name = "domains_subscriber" +path = "rust/domains/subscriber.rs" + +[[example]] +name = "domains_discovery" +path = "rust/domains/discovery.rs" diff --git a/examples/README.md b/examples/README.md index a6e1ef51b..546ba26aa 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,6 +48,7 @@ they interact and exchange data. | complex data types | [Rust](rust/complex_data_types) | Send zero-copy compatible versions of `Vec` and `String`. Introduces `PlacementDefault` trait for large data types to perform an in place initialization where otherwise a stack overflow would be encountered.| | discovery | [C](c/discovery) [C++](cxx/discovery) [Rust](rust/discovery) | List all available services in a system. | | docker | [all](rust/docker) | Communicate between different docker containers and the host. | +| domains | [Rust](rust/domains) | Establish separate domains that operate independently from one another. | | event | [C](c/event) [C++](cxx/event) [Rust](rust/event) | Push notifications - send event signals to wakeup processes that are waiting for them.| | publish subscribe | [C](c/publish_subscribe) [C++](cxx/publish_subscribe) [Rust](rust/publish_subscribe) | Communication between multiple processes with a [publish subscribe messaging pattern](https://en.wikipedia.org/wiki/Publish–subscribe_pattern). | | publish subscribe dynamic data | [Rust](rust/publish_subscribe_dynamic_data) | Communication between multiple processes with a [publish subscribe messaging pattern](https://en.wikipedia.org/wiki/Publish–subscribe_pattern) and payload data that has a dynamic size. | diff --git a/examples/rust/domains/README.md b/examples/rust/domains/README.md new file mode 100644 index 000000000..78ec2747b --- /dev/null +++ b/examples/rust/domains/README.md @@ -0,0 +1,24 @@ +# Domains + +## Running The Example + +**Terminal 1** + +```sh +cargo run --example domains_subscriber -- -d "fuu" -s "bar" +``` + +**Terminal 2** + +```sh +cargo run --example domains_publisher -- -d "fuu" -s "bar" +``` + +**Terminal 3** + +```sh +cargo run --example domains_discovery -- -d "fuu" +``` + + + diff --git a/examples/rust/domains/discovery.rs b/examples/rust/domains/discovery.rs new file mode 100644 index 000000000..9c6ed221d --- /dev/null +++ b/examples/rust/domains/discovery.rs @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use clap::Parser; +use iceoryx2::prelude::*; +use iceoryx2_bb_log::{set_log_level, LogLevel}; +use iceoryx2_bb_system_types::file_name::*; + +fn main() -> Result<(), Box> { + let args = parse_args(); + + let mut config = Config::global_config().clone(); + config.global.prefix = FileName::new(args.domain.as_bytes())?; + + println!("\nServices running in domain \"{}\":", args.domain); + ipc::Service::list(&config, |service| { + println!(" {}", &service.static_details.name()); + CallbackProgression::Continue + })?; + + Ok(()) +} + +///////////////////////////////// +// uninteresting part, contains +// * arguments parsing +// * log level setup +///////////////////////////////// + +#[derive(Parser, Debug)] +struct Args { + /// The name of the domain. Must be a valid file name. + #[clap(short, long, default_value = "iox2")] + domain: String, + /// Enable full debug log output + #[clap(long, default_value_t = false)] + debug: bool, +} + +fn define_log_level(args: &Args) { + if args.debug { + set_log_level(LogLevel::Trace); + } else { + set_log_level(LogLevel::Warn); + } +} + +fn parse_args() -> Args { + let args = Args::parse(); + define_log_level(&args); + args +} diff --git a/examples/rust/domains/publisher.rs b/examples/rust/domains/publisher.rs new file mode 100644 index 000000000..b843775f1 --- /dev/null +++ b/examples/rust/domains/publisher.rs @@ -0,0 +1,104 @@ +// Copyright (c) 2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use clap::Parser; +use core::time::Duration; +use examples_common::TransmissionData; +use iceoryx2::prelude::*; +use iceoryx2_bb_log::{set_log_level, LogLevel}; +use iceoryx2_bb_system_types::file_name::*; + +const CYCLE_TIME: Duration = Duration::from_secs(1); + +fn main() -> Result<(), Box> { + let args = parse_args(); + + // create a new config based on the global config + let mut config = Config::global_config().clone(); + + // The domain name becomes the prefix for all resources. + // Therefore, different domain names never share the same resources. + config.global.prefix = FileName::new(args.domain.as_bytes())?; + + let node = NodeBuilder::new() + // use the custom config when creating the custom node + // every service constructed by the node will use this config + .config(&config) + .create::()?; + + //////////////////////////////////////////////////////////////// + // from here on it is the publish_subscribe publisher example + //////////////////////////////////////////////////////////////// + let service = node + .service_builder(&args.service.as_str().try_into()?) + .publish_subscribe::() + .open_or_create()?; + + let publisher = service.publisher_builder().create()?; + + let mut counter: u64 = 0; + + while let NodeEvent::Tick = node.wait(CYCLE_TIME) { + counter += 1; + let sample = publisher.loan_uninit()?; + + let sample = sample.write_payload(TransmissionData { + x: counter as i32, + y: counter as i32 * 3, + funky: counter as f64 * 812.12, + }); + + sample.send()?; + + println!( + "[domain: \"{}\", service: \"{}\"] Send sample {} ...", + args.domain, args.service, counter + ); + } + + println!("exit"); + + Ok(()) +} + +///////////////////////////////// +// uninteresting part, contains +// * arguments parsing +// * log level setup +///////////////////////////////// + +#[derive(Parser, Debug)] +struct Args { + /// The name of the domain. Must be a valid file name. + #[clap(short, long, default_value = "iox2")] + domain: String, + /// The of the service. + #[clap(short, long, default_value = "my_funky_service")] + service: String, + /// Enable full debug log output + #[clap(long, default_value_t = false)] + debug: bool, +} + +fn define_log_level(args: &Args) { + if args.debug { + set_log_level(LogLevel::Trace); + } else { + set_log_level(LogLevel::Warn); + } +} + +fn parse_args() -> Args { + let args = Args::parse(); + define_log_level(&args); + args +} diff --git a/examples/rust/domains/subscriber.rs b/examples/rust/domains/subscriber.rs new file mode 100644 index 000000000..0a55ea24d --- /dev/null +++ b/examples/rust/domains/subscriber.rs @@ -0,0 +1,91 @@ +// Copyright (c) 2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use clap::Parser; +use core::time::Duration; +use examples_common::TransmissionData; +use iceoryx2::prelude::*; +use iceoryx2_bb_log::{set_log_level, LogLevel}; +use iceoryx2_bb_system_types::file_name::*; + +const CYCLE_TIME: Duration = Duration::from_secs(1); + +fn main() -> Result<(), Box> { + let args = parse_args(); + + // create a new config based on the global config + let mut config = Config::global_config().clone(); + + // The domain name becomes the prefix for all resources. + // Therefore, different domain names never share the same resources. + config.global.prefix = FileName::new(args.domain.as_bytes())?; + + let node = NodeBuilder::new() + // use the custom config when creating the custom node + // every service constructed by the node will use this config + .config(&config) + .create::()?; + + let service = node + .service_builder(&args.service.as_str().try_into()?) + .publish_subscribe::() + .open_or_create()?; + + let subscriber = service.subscriber_builder().create()?; + + println!( + "subscribed to: [domain: \"{}\", service: \"{}\"]", + args.domain, args.service + ); + while let NodeEvent::Tick = node.wait(CYCLE_TIME) { + while let Some(sample) = subscriber.receive()? { + println!("received: {:?}", *sample); + } + } + + println!("exit"); + + Ok(()) +} + +///////////////////////////////// +// uninteresting part, contains +// * arguments parsing +// * log level setup +///////////////////////////////// + +#[derive(Parser, Debug)] +struct Args { + /// The name of the domain. Must be a valid file name. + #[clap(short, long, default_value = "iox2")] + domain: String, + /// The of the service. + #[clap(short, long, default_value = "my_funky_service")] + service: String, + /// Enable full debug log output + #[clap(long, default_value_t = false)] + debug: bool, +} + +fn define_log_level(args: &Args) { + if args.debug { + set_log_level(LogLevel::Trace); + } else { + set_log_level(LogLevel::Warn); + } +} + +fn parse_args() -> Args { + let args = Args::parse(); + define_log_level(&args); + args +} From fdd3ac1257c81f1f64c54837d7d9e09857433113 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 6 Sep 2024 09:53:37 +0200 Subject: [PATCH 2/2] [#370] Write documentation --- examples/rust/domains/README.md | 46 ++++++++++++++++++++++++++---- examples/rust/domains/discovery.rs | 6 ++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/examples/rust/domains/README.md b/examples/rust/domains/README.md index 78ec2747b..c63c27ca2 100644 --- a/examples/rust/domains/README.md +++ b/examples/rust/domains/README.md @@ -1,24 +1,58 @@ # Domains +Let's assume you want to create multiple iceoryx2 groups of processes where the +processes inside a group can communicate and interact with each other. However, +the groups themselves should remain isolated, meaning a process from one group +cannot interact with a process from another group. + +In other words, we aim to create different iceoryx2 domains on a local machine +that are strictly separated. + +This strict separation can be achieved by using the iceoryx2 configuration. +Within the configuration, a wide range of parameters can be adjusted, such as +the directory used for files containing static service information (a detailed +description of the service) or static node information (a detailed description +of a node). Additionally, the prefix of all files, which is by default `iox2_`, +can be modified. + +In this example, we use the prefix to separate the iceoryx2 groups. For all +examples, the user can set the iceoryx2 domain using `-d $DOMAIN_NAME$`. The +domain name must be a valid file name. The example will only operate within +this domain and cannot interact with any services in other domains with +different names. + +The `domains_discovery` binary illustrates this by listing all services +available in a given domain. Similarly, the `domains_publisher` will send data +only to subscribers within the same domain. Subscribers in other domains will +not receive any data. + +## Implementation + +To achieve this, we create a copy of the global configuration, modify the +setting `config.global.prefix` using the user-provided CLI argument, and then +set up the example accordingly. + ## Running The Example -**Terminal 1** +You can experiment with this setup by creating multiple publishers and +subscribers with different service names using `-s $SERVICE_NAME`. Only +publisher-subscriber pairs within the same domain will be able to communicate, +and the discovery tool will only detect services from within the same domain. + +**Terminal 1:** Subscriber in domain "fuu" subscribing to service "bar" ```sh cargo run --example domains_subscriber -- -d "fuu" -s "bar" ``` -**Terminal 2** +**Terminal 2** Publisher in domain "fuu" publishing on service "bar" ```sh cargo run --example domains_publisher -- -d "fuu" -s "bar" ``` -**Terminal 3** +**Terminal 3** List all services of domain "fuu" ```sh cargo run --example domains_discovery -- -d "fuu" ``` - - - diff --git a/examples/rust/domains/discovery.rs b/examples/rust/domains/discovery.rs index 9c6ed221d..20949b916 100644 --- a/examples/rust/domains/discovery.rs +++ b/examples/rust/domains/discovery.rs @@ -18,10 +18,16 @@ use iceoryx2_bb_system_types::file_name::*; fn main() -> Result<(), Box> { let args = parse_args(); + // create a new config based on the global config let mut config = Config::global_config().clone(); + + // The domain name becomes the prefix for all resources. + // Therefore, different domain names never share the same resources. config.global.prefix = FileName::new(args.domain.as_bytes())?; println!("\nServices running in domain \"{}\":", args.domain); + + // use the custom config when listing the services ipc::Service::list(&config, |service| { println!(" {}", &service.static_details.name()); CallbackProgression::Continue