Skip to content

Commit

Permalink
Merge pull request #373 from elfenpiff/iox2-370-domain-separation-exa…
Browse files Browse the repository at this point in the history
…mple

[#370] domain separation example
  • Loading branch information
elfenpiff authored Sep 13, 2024
2 parents 2d1f01d + fdd3ac1 commit 2fe0403
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 0 deletions.
17 changes: 17 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down
58 changes: 58 additions & 0 deletions examples/rust/domains/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +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

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** Publisher in domain "fuu" publishing on service "bar"

```sh
cargo run --example domains_publisher -- -d "fuu" -s "bar"
```

**Terminal 3** List all services of domain "fuu"

```sh
cargo run --example domains_discovery -- -d "fuu"
```
67 changes: 67 additions & 0 deletions examples/rust/domains/discovery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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<dyn std::error::Error>> {
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
})?;

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
}
104 changes: 104 additions & 0 deletions examples/rust/domains/publisher.rs
Original file line number Diff line number Diff line change
@@ -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<dyn std::error::Error>> {
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::<ipc::Service>()?;

////////////////////////////////////////////////////////////////
// from here on it is the publish_subscribe publisher example
////////////////////////////////////////////////////////////////
let service = node
.service_builder(&args.service.as_str().try_into()?)
.publish_subscribe::<TransmissionData>()
.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
}
91 changes: 91 additions & 0 deletions examples/rust/domains/subscriber.rs
Original file line number Diff line number Diff line change
@@ -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<dyn std::error::Error>> {
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::<ipc::Service>()?;

let service = node
.service_builder(&args.service.as_str().try_into()?)
.publish_subscribe::<TransmissionData>()
.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
}

0 comments on commit 2fe0403

Please sign in to comment.