Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ env:
CARGO_TERM_COLOR: always

jobs:
e2e-tests:
e2e-test:
name: End-to-End Tests
runs-on: ubuntu-latest

Expand All @@ -24,5 +24,18 @@ jobs:
run: docker build -t distributed-topic-tracker .

- name: Run end-to-end test
run: ./test-e2e.sh
run: COMPOSE_FILE=./docker-compose.yml ./test-e2e.sh

e2e-test-experimental:
name: End-to-End Tests (Experimental)
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: docker build -t distributed-topic-tracker --file Dockerfile.experimental .

- name: Run end-to-end test
run: COMPOSE_FILE=./docker-compose-experimental.yml ./test-e2e.sh

23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ edition = "2024"
[features]
default = ["iroh-gossip"]
iroh-gossip = ["dep:iroh", "dep:iroh-gossip"]
experimental = ["dep:mainline_exp"]


[dependencies]
Expand All @@ -32,7 +33,6 @@ futures-lite = "2"

chrono = { version = "0.4", default-features = false, features = ["clock"] }

mainline = { version = "6", default-features = false, features = ["async"]}
rand = { version = "0.9", default-features = false, features = ["std", "std_rng"] }
actor-helper = { version = "0.2", features = ["tokio", "anyhow"] }
postcard = "1"
Expand All @@ -41,6 +41,11 @@ serde = { version = "1", default-features = false, features = ["std"] }
tracing = { version = "0.1", default-features = false, features = ["std"] }
tracing-subscriber = { version = "0.3", default-features = false, features = ["std", "env-filter", "ansi"] }

mainline = { version = "6.0.0", default-features = false, features = ["async"] }
mainline_exp = { git = "https://github.com/Nuhvi/mainline", branch = "main", default-features = false, features = ["async"], optional = true, package = "dht" }

hex = "0.4"

[lib]
crate-type = ["cdylib", "rlib"]

Expand All @@ -52,6 +57,7 @@ required-features = ["iroh-gossip"]
name = "tests"

# only build examples if the "iroh-gossip" feature is enabled

[[example]]
name = "chat"
required-features = ["iroh-gossip"]
Expand All @@ -71,3 +77,11 @@ required-features = ["iroh-gossip"]
[[example]]
name = "simple"
required-features = ["iroh-gossip"]

[[example]]
name = "chat_experimental"
required-features = ["iroh-gossip", "experimental"]

[[example]]
name = "e2e_test_experimental"
required-features = ["iroh-gossip", "experimental"]
26 changes: 26 additions & 0 deletions Dockerfile.experimental
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM rust:1.89.0 as builder

WORKDIR /app

COPY Cargo.toml Cargo.lock ./
COPY README.md ./
COPY src ./src
COPY tests ./tests
COPY examples ./examples

# test then build
RUN cargo build --release --example e2e_test_experimental --features="iroh-gossip experimental"

# create a minimal runtime image
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*



# Copy the built binary from the builder stage
COPY --from=builder /app/target/release/examples/e2e_test_experimental /usr/local/bin/e2e_test_experimental

# Set the default command
CMD ["e2e_test_experimental"]
34 changes: 34 additions & 0 deletions docker-compose-experimental.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
node1:
build:
context: .
dockerfile: Dockerfile.experimental
container_name: dtt-node1
environment:
- RUST_LOG=info
- TOPIC_ID=${TOPIC_ID}
command: sh -c "e2e_test_experimental 2 $${TOPIC_ID}"

node2:
build:
context: .
dockerfile: Dockerfile.experimental
container_name: dtt-node2
environment:
- RUST_LOG=info
- TOPIC_ID=${TOPIC_ID}
command: sh -c "sleep 10 && e2e_test_experimental 2 $${TOPIC_ID}"
depends_on:
- node1

node3:
build:
context: .
dockerfile: Dockerfile.experimental
container_name: dtt-node3
environment:
- RUST_LOG=info
- TOPIC_ID=${TOPIC_ID}
command: sh -c "sleep 20 && e2e_test_experimental 2 $${TOPIC_ID}"
depends_on:
- node2
20 changes: 8 additions & 12 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,23 @@ services:
container_name: dtt-node1
environment:
- RUST_LOG=info
command: >
sh -c "echo 'Starting node1...' &&
sleep 2 &&
e2e_test"
command: sh -c "e2e_test"

node2:
build: .
container_name: dtt-node2
environment:
- RUST_LOG=info
command: >
sh -c "echo 'Starting node2...' &&
sleep 5 &&
e2e_test"
command: sh -c "sleep 10 && e2e_test"
depends_on:
- node1


node3:
build: .
container_name: dtt-node3
environment:
- RUST_LOG=info
command: >
sh -c "echo 'Starting node3...' &&
sleep 8 &&
e2e_test"
command: sh -c "sleep 20 && e2e_test"
depends_on:
- node1
81 changes: 81 additions & 0 deletions examples/chat_experimental.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use anyhow::Result;
use distributed_topic_tracker::AutoDiscoveryGossip;
use iroh::{Endpoint, SecretKey};
use iroh_gossip::{api::Event, net::Gossip};

use ed25519_dalek::SigningKey;

// Imports from distrubuted-topic-tracker

#[tokio::main]
async fn main() -> Result<()> {
// tracing init - only show distributed_topic_tracker logs
use tracing_subscriber::filter::EnvFilter;

tracing_subscriber::fmt()
.with_thread_ids(true)
.with_ansi(true)
.with_env_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("distributed_topic_tracker=debug")),
)
.init();

// Generate a new random secret key
let secret_key = SecretKey::generate(&mut rand::rng());
let signing_key = SigningKey::from_bytes(&secret_key.to_bytes());

// Set up endpoint with discovery enabled
let endpoint = Endpoint::builder()
.secret_key(secret_key.clone())
.bind()
.await?;

// Initialize gossip with auto-discovery
let gossip = Gossip::builder().spawn(endpoint.clone());

// Set up protocol router
let _router = iroh::protocol::Router::builder(endpoint.clone())
.accept(iroh_gossip::ALPN, gossip.clone())
.spawn();

let topic_id = "my-iroh-gossip-topic-experimental".as_bytes().to_vec();

// Split into sink (sending) and stream (receiving)
let (gossip_sender, gossip_receiver) = gossip
.subscribe_and_join_with_auto_discovery(topic_id, signing_key)
.await?
.split()
.await;

println!("Joined topic");

// Spawn listener for incoming messages
tokio::spawn(async move {
while let Some(Ok(event)) = gossip_receiver.next().await {
if let Event::Received(msg) = event {
println!(
"\nMessage from {}: {}",
&msg.delivered_from.to_string()[0..8],
String::from_utf8(msg.content.to_vec()).unwrap()
);
} else if let Event::NeighborUp(peer) = event {
println!("\nJoined by {}", &peer.to_string()[0..8]);
}
}
});

// Main input loop for sending messages
let mut buffer = String::new();
let stdin = std::io::stdin();
loop {
print!("\n> ");
stdin.read_line(&mut buffer).unwrap();
gossip_sender
.broadcast(buffer.clone().replace("\n", "").into())
.await
.unwrap();
println!(" - (sent)");
buffer.clear();
}
}
2 changes: 1 addition & 1 deletion examples/chat_no_wait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use iroh_gossip::{api::Event, net::Gossip};

// Imports from distrubuted-topic-tracker
use distributed_topic_tracker::{AutoDiscoveryGossip, RecordPublisher, TopicId};
use mainline::SigningKey;
use ed25519_dalek::SigningKey;

#[tokio::main]
async fn main() -> Result<()> {
Expand Down
4 changes: 3 additions & 1 deletion examples/e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ use anyhow::Result;
use iroh::{Endpoint, SecretKey};
use iroh_gossip::net::Gossip;

use ed25519_dalek::SigningKey;

// Imports from distrubuted-topic-tracker
use distributed_topic_tracker::{AutoDiscoveryGossip, RecordPublisher, TopicId};

#[tokio::main]
async fn main() -> Result<()> {
// Generate a new random secret key
let secret_key = SecretKey::generate(&mut rand::rng());
let signing_key = mainline::SigningKey::from_bytes(&secret_key.to_bytes());
let signing_key = SigningKey::from_bytes(&secret_key.to_bytes());

// Set up endpoint with discovery enabled
let endpoint = Endpoint::builder()
Expand Down
Loading