Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
12 changes: 12 additions & 0 deletions tonic-xds/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fastrand = "2"
tokio-stream = "0.1"
backoff = "0.4"
shared_http_body = "0.1"
tonic-prost = { version = "0.14", optional = true }

[lints]
workspace = true
Expand All @@ -54,3 +55,14 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "net"] }
tonic = { version = "0.14", features = [ "server", "channel", "tls-ring" ] }
tonic-prost = "0.14"
tonic-prost-build = "0.14"

[features]
testutil = ["dep:tonic-prost"]

[[example]]
name = "channel"
required-features = ["testutil"]

[[example]]
name = "greeter_server"
required-features = ["testutil"]
64 changes: 64 additions & 0 deletions tonic-xds/examples/channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! Example: send gRPC requests through an xDS-aware channel.
//!
//! Builds an xDS channel, then sends HelloRequest RPCs through it in a loop.
//! The channel discovers endpoints via the xDS management server and
//! load-balances across them.
//!
//! # Prerequisites
//!
//! 1. Start one or more greeter backends:
//! ```sh
//! PORT=50051 cargo run -p tonic-xds --example greeter_server
Comment thread
YutaoMa marked this conversation as resolved.
Outdated
//! ```
//!
//! 2. Start an xDS control plane (e.g., go-control-plane) configured to
Comment thread
YutaoMa marked this conversation as resolved.
Outdated
//! return LDS/RDS/CDS/EDS pointing at the greeter backends.
//!
//! # Configuration
//!
//! - `GRPC_XDS_BOOTSTRAP` — path to a bootstrap JSON file, **or**
//! - `GRPC_XDS_BOOTSTRAP_CONFIG` — inline bootstrap JSON
//! - `XDS_TARGET` — xDS target URI (default: `xds:///my-service`)
//!
//! # Usage
//!
//! ```sh
//! GRPC_XDS_BOOTSTRAP_CONFIG='{"xds_servers":[{"server_uri":"localhost:18000"}],"node":{"id":"test"}}' \
//! cargo run -p tonic-xds --example channel
//! ```

use tonic_xds::testutil::proto::helloworld::{HelloRequest, greeter_client::GreeterClient};
use tonic_xds::{XdsChannelBuilder, XdsChannelConfig, XdsUri};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let target_str = std::env::var("XDS_TARGET").unwrap_or_else(|_| "xds:///my-service".into());
let target = XdsUri::parse(&target_str)?;

println!("Building xDS channel for target: {target_str}");

let channel = XdsChannelBuilder::new(XdsChannelConfig::new(target)).build_grpc_channel()?;

let mut client = GreeterClient::new(channel);

println!("Channel built. Sending requests (Ctrl-C to stop)...\n");

for i in 1.. {
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
Comment thread
YutaoMa marked this conversation as resolved.
Outdated

let request = HelloRequest {
name: format!("request-{i}"),
};

match client.say_hello(request).await {
Ok(response) => {
println!("[{i}] Response: {}", response.into_inner().message);
}
Err(status) => {
eprintln!("[{i}] Error: {status}");
}
}
}

Ok(())
}
61 changes: 61 additions & 0 deletions tonic-xds/examples/greeter_server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Example: standalone gRPC greeter server for testing xDS.
//!
//! Starts a greeter backend on a given port. Point your xDS control plane's
//! EDS config at this server's address, then use the `channel` example to
//! send requests through the xDS channel.
//!
//! # Usage
//!
//! ```sh
//! # Start a backend on port 50051 (default):
//! cargo run -p tonic-xds --example greeter_server
//!
//! # Start on a custom port:
//! PORT=50052 cargo run -p tonic-xds --example greeter_server
//!
//! # Start multiple backends:
//! PORT=50051 cargo run -p tonic-xds --example greeter_server &
//! PORT=50052 cargo run -p tonic-xds --example greeter_server &
//! ```

use tonic::transport::Server;
use tonic::{Request, Response, Status};
use tonic_xds::testutil::proto::helloworld::{
HelloReply, HelloRequest,
greeter_server::{Greeter, GreeterServer},
};

struct MyGreeter {
addr: String,
}

#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let name = request.into_inner().name;
println!("Received request: name={name}");
Ok(Response::new(HelloReply {
message: format!("Hello {name} from {}", self.addr),
}))
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let port = std::env::var("PORT").unwrap_or_else(|_| "50051".to_string());
let addr: std::net::SocketAddr = format!("0.0.0.0:{port}").parse()?;

println!("Greeter server listening on {addr}");

Server::builder()
.add_service(GreeterServer::new(MyGreeter {
addr: addr.to_string(),
}))
.serve(addr)
.await?;

Ok(())
}
Loading
Loading