### Rust Async Key-Value Store Get Request Example Source: https://docs.iroh.computer/protocols/rpc Illustrates how to send a Get request to an asynchronous key-value store and await its response. This involves creating a oneshot channel and sending the request through an mpsc sender. ```rust let (tx, rx) = oneshot::channel(); client.send(Request::Get { key: "a".to_string(), response: tx }).await?; let res = rx.await?; ``` -------------------------------- ### Start Iroh Listener with Custom Protocol Source: https://docs.iroh.computer/protocols/writing-a-protocol Initializes an Iroh endpoint, creates a Router, and configures it to accept incoming connections for a specific ALPN using a custom `ProtocolHandler`. The router is then spawned to start listening. ```rust async fn start_accept_side() -> anyhow::Result { let endpoint = iroh::Endpoint::bind().await?; let router = iroh::protocol::Router::builder(endpoint) .accept(ALPN, Echo) // This makes the router handle incoming connections with our ALPN via Echo::accept! .spawn(); Ok(router) } ``` -------------------------------- ### Install futures-lite crate Source: https://docs.iroh.computer/examples/chat This command installs the `futures-lite` crate, which is used to simplify handling asynchronous streams in Rust. It's a subset of the `futures` crate and provides the `StreamExt` trait for easier stream manipulation. ```bash cargo add futures-lite ``` -------------------------------- ### Rust: Main Function to Orchestrate QUIC Connection Source: https://docs.iroh.computer/protocols/writing-a-protocol A main function in Rust that orchestrates the QUIC protocol by starting the accepting side, connecting to it using the `connect_side` function, and then shutting down the accepting side gracefully. This example utilizes `tokio` for asynchronous operations. ```rust #[tokio::main] async fn main() -> Result<()> { let router = start_accept_side().await?; let endpoint_addr = router.endpoint().addr().await?; connect_side(endpoint_addr).await?; // This makes sure the endpoint in the router is closed properly and connections close gracefully router.shutdown().await?; Ok(()) } ``` -------------------------------- ### Receiver Role: Setup and Run in Rust Source: https://docs.iroh.computer/quickstart Sets up and runs the receiver component of the iroh application. It binds an endpoint, brings it online, prints its ticket, and starts a router to accept incoming ping requests. ```rust // filepath: src/main.rs use anyhow::{anyhow, Result}; use iroh::{Endpoint, protocol::Router}; use iroh_ping::Ping; use iroh_tickets::{Ticket, endpoint::EndpointTicket}; use std::env; async fn run_receiver() -> Result<()> { // Create an endpoint, it allows creating and accepting // connections in the iroh p2p world let endpoint = Endpoint::bind().await?; // Wait for the endpoint to be accessible by others on the internet endpoint.online().await; // Then we initialize a struct that can accept ping requests over iroh connections let ping = Ping::new(); // get the address of this endpoint to share with the sender let ticket = EndpointTicket::new(endpoint.addr()); println!("{}", ticket); // receiving ping requests let _router = Router::builder(endpoint) .accept(iroh_ping::ALPN, ping) .spawn(); // Keep the receiver running until Ctrl+C tokio::signal::ctrl_c().await?; Ok(()) } ``` -------------------------------- ### Run iroh streaming demo (Bash) Source: https://docs.iroh.computer/protocols/streaming Demonstrates how to clone the 'callme' repository and run the command-line client in server/listen mode and connect to a peer. This requires the Rust toolchain and 'cargo' to be installed. ```bash git clone https://github.com/n0-computer/callme.git # Terminal A: run the CLI in server/listen mode cd callme/callme-cli cargo run --release -- --listen # Terminal B: run the CLI and connect to the other peer's address cd callme/callme-cli cargo run --release -- --connect ``` -------------------------------- ### Clone and Navigate Iroh Automerge Example Source: https://docs.iroh.computer/protocols/automerge This snippet demonstrates how to clone the iroh-examples repository and navigate into the iroh-automerge directory to begin the integration process. ```bash git clone https://github.com/n0-computer/iroh-examples cd iroh-examples/iroh-automerge ``` -------------------------------- ### Initialize Iroh Endpoint and Protocols (Rust) Source: https://docs.iroh.computer/protocols/kv-crdts This Rust example demonstrates setting up an Iroh endpoint, initializing the Gossip and Docs protocols, and configuring a router to handle these protocols over peer-to-peer connections. It uses in-memory storage for the Docs protocol. ```rust use iroh::{protocol::Router, Endpoint}; use iroh_blobs::{BlobsProtocol, store::mem::MemStore, ALPN as BLOBS_ALPN}; use iroh_docs::{protocol::Docs, ALPN as DOCS_ALPN}; use iroh_gossip::{net::Gossip, ALPN as GOSSIP_ALPN}; #[tokio::main] async fn main() -> anyhow::Result<()> { // create an iroh endpoint that includes the standard discovery mechanisms // we've built at number0 let endpoint = Endpoint::builder().bind().await?; // build the gossip protocol let gossip = Gossip::builder().spawn(endpoint.clone()); // build the docs protocol // use Docs::persistent to use local storage let docs = Docs::memory() .spawn(endpoint.clone(), (*blobs).clone(), gossip.clone()) .await?; // create a router builder, we will add the // protocols to this builder and then spawn // the router let builder = Router::builder(endpoint.clone()); // setup router let _router = builder .accept(GOSSIP_ALPN, gossip) .accept(DOCS_ALPN, docs) .spawn(); // do fun stuff with docs! Ok(()) } ``` -------------------------------- ### Run the Ping-Pong Program and View Output Source: https://docs.iroh.computer/quickstart Provides instructions on how to compile and run the completed ping-pong program using Cargo. It also shows an example of the expected output, including the measured ping latency. ```bash cargo run I Compiling ping-pong v0.1.0 (/dev/ping-pong) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.62s Running `target/debug/ping-pong` ping took: 1.189375ms to complete ``` -------------------------------- ### Install clap Crate for CLI Argument Parsing Source: https://docs.iroh.computer/examples/chat This command installs the 'clap' crate, a popular Rust library for parsing command-line arguments. The '--features derive' flag enables the derive API, which simplifies the process of defining command-line structures. ```bash cargo add clap --features derive ``` -------------------------------- ### Example: Gossip Broadcast in Rust Source: https://docs.iroh.computer/connecting/gossip This Rust code demonstrates how to set up an iroh endpoint, build and spawn the gossip protocol, subscribe to a topic, broadcast a message, and receive messages. It requires the 'iroh', 'iroh-gossip', 'n0-error', and 'n0-future' crates. The example includes basic error handling and asynchronous operations using tokio. ```rust use iroh::{protocol::Router, Endpoint, EndpointId}; use iroh_gossip::{api::Event, Gossip, TopicId}; use n0_error::{Result, StdResultExt}; use n0_future::StreamExt; #[tokio::main] async fn main() -> Result<()> { // create an iroh endpoint that includes the standard discovery mechanisms // we've built at number0 let endpoint = Endpoint::bind().await?; // build gossip protocol let gossip = Gossip::builder().spawn(endpoint.clone()); // setup router let router = Router::builder(endpoint) .accept(iroh_gossip::ALPN, gossip.clone()) .spawn(); // gossip swarms are centered around a shared "topic id", which is a 32 byte identifier let topic_id = TopicId::from_bytes([23u8; 32]); // and you need some bootstrap peers to join the swarm let bootstrap_peers = bootstrap_peers(); // then, you can subscribe to the topic and join your initial peers let (sender, mut receiver) = gossip .subscribe(topic_id, bootstrap_peers) .await? .split(); // you might want to wait until you joined at least one other peer: receiver.joined().await?; // then, you can broadcast messages to all other peers! sender.broadcast(b"hello world this is a gossip message".to_vec().into()).await?; // and read messages from others while let Some(event) = receiver.next().await { match event? { Event::Received(message) => { println!("received a message: {:?}", std::str::from_utf8(&message.content)); } _ => {} } } // clean shutdown makes sure that other peers are notified that you went offline router.shutdown().await.std_context("shutdown router")?; Ok(()) } fn bootstrap_peers() -> Vec { // insert your bootstrap peers here, or get them from your environment vec![] } ``` -------------------------------- ### Example Output of Ticket Generation (Bash) Source: https://docs.iroh.computer/examples/chat This bash output shows an example of what the printed ticket looks like when the Rust code is executed. It includes the endpoint ID and a long string representing the ticket itself. ```bash > our endpoint id: 03ce2e2f55af140d0b18395fff054d3f3ab6a30aa680e4a2a3ab4526838151a5 > ticket to join us: pmrhi33qnfrseos3ge4tslbthawdcojvfq3tolbrgq4symjufqytinbmg4wdemzzfqzdinjmgiztmlbshewdonbmgiztglbrgi4cynzzfqzdslbxgqwdsnrmgizdmlbsgazsymjzgewdemzzfqytqmjmgiytalbsguysyobzfqytclbvgiwdenbwfq2cymjygbosyiton5sgk4zchjnxwiton5sgkx3jmqrduirqgnrwkmtfgjtdknlbmyytimdegbrdcobthe2wmztgga2tizbtmyzwcyrwmeztaylbgy4dazjumezgcm3bmi2dkmrwhaztqmjvgfqtkirmejzgk3dbpfpxk4tmei5ce2duoryhgorpf52xgzjrfuys44tfnrqxsltjojxwqltomv2ho33snmxc6irmejsgs4tfmn2f6ylemrzgk43tmvzseos3ei3tilrxgmxdkmroge2dqorvguzdomzcfqrdcojsfyytmobogexdemr2gu2tenzteiwcewzsgyydgorxgaydaoryg4zwcotdmjsdmorrmnsgiorwge2dqorxmnrgcoteha4wgxj2gu2tenzueiwcewzsgyydgorxgaydaoryg4zwcotdmjsdmotggu4teorshfrtaotbgzqtgotbha4tsxj2gu2tenzuejox2xl5 > type a message and hit enter to broadcast... ``` -------------------------------- ### Install iroh-docs with Cargo Source: https://docs.iroh.computer/protocols/kv-crdts This command adds the `iroh-docs` crate as a dependency to your Rust project using Cargo, the Rust package manager. ```bash cargo add iroh-docs ``` -------------------------------- ### Run Application Command (Bash) Source: https://docs.iroh.computer/examples/chat This command demonstrates how to run the Iroh chat application from the command line using Cargo. The `--name user1 open` arguments specify the user's name and the action to open a new chat room. This is the command to start a new chat session. ```bash cargo run -- --name user1 open ``` -------------------------------- ### Rust Async Client Wrapper for Message Passing Source: https://docs.iroh.computer/protocols/rpc Shows a Rust client struct that wraps an mpsc::Sender to provide a more convenient API for sending requests. The `get` method demonstrates simplifying the request-response pattern. ```rust struct Client(mpsc::Sender); impl Client { ... async fn get(&self, key: String) -> Result> { let (tx, rx) = oneshot::channel(); self.0.send(Request::Get { key, response: tx }).await?; Ok(rx.await??) } ... } ``` -------------------------------- ### Create Multi-Provider Channel and Spawn Input Loop (Rust) Source: https://docs.iroh.computer/examples/chat This snippet demonstrates how to create a multi-provider, single-consumer channel using `tokio::sync::mpsc::channel`. It then spawns a new thread to run the `input_loop` function, passing the sender half of the channel to it. This setup allows multiple threads to send messages to a single receiver. ```rust // create a multi-provider, single-consumer channel let (line_tx, mut line_rx) = tokio::sync::mpsc::channel(1); // and pass the `sender` portion to the `input_loop` std::thread::spawn(move || input_loop(line_tx)); ``` -------------------------------- ### Create and Bind an iroh Endpoint (Rust) Source: https://docs.iroh.computer/connecting/creating-endpoint Initializes a new iroh endpoint and binds it to a local address, allowing it to listen for incoming connections. The `bind` method creates the endpoint and starts listening, while `await` is used in an asynchronous context. ```rust use iroh::Endpoint; #[tokio::main] async fn main() { let endpoint = Endpoint::bind().await?; // ... } ``` -------------------------------- ### Local vs. Remote Client Implementation in Rust Source: https://docs.iroh.computer/protocols/rpc This Rust code defines a `Client` enum that can represent either a local client using an MPSC channel or a remote client using a QUIC connection. The `get` method demonstrates how to handle requests differently based on the client type, abstracting away the underlying communication mechanism. ```rust enum Client { Local(mpsc::Sender), Remote(quinn::Connection), } impl Client { async fn get(&self, key: String) -> Result> { let request = GetRequest { key }; match self { Self::Local(chan) => { let (tx, rx) = oneshot::channel(); let request = FullRequest { request, response: tx }; chan.send(request).await?; Ok(rx.await??) } Self::Remote(conn) => { let (send, recv) = conn.open_bi().await?; send.write_all(postcard::to_stdvec(request)?).await?; let res = recv.read_to_end(1024).await?; let res = postcard::from_bytes(&res)?; Ok(res) } } } } ``` -------------------------------- ### Initialize Iroh Router for Listening Source: https://docs.iroh.computer/protocols/writing-a-protocol Sets up the initial Iroh Router for the accepting side of the protocol. It binds to an endpoint and prepares the router, with the intention of later configuring it to accept specific protocols. ```rust async fn start_accept_side() -> anyhow::Result { let endpoint = iroh::Endpoint::bind().await?; let router = iroh::protocol::Router::builder(endpoint) .spawn(); Ok(router) } ``` -------------------------------- ### Install iroh-doctor CLI Source: https://docs.iroh.computer/deployment/troubleshooting Installs the `iroh-doctor` command-line tool using Cargo. This tool is used for diagnosing network connectivity issues with your iroh setup. ```bash cargo install iroh-doctor ``` -------------------------------- ### Initialize Rust Project and Add Dependencies Source: https://docs.iroh.computer/quickstart Sets up a new Rust project using Cargo and adds necessary iroh and tokio dependencies. This is the initial step for building the ping application. ```bash cargo init ping-pong cd ping-pong cargo add iroh iroh-ping iroh-tickets tokio anyhow ``` -------------------------------- ### Install iroh-gossip Crate Source: https://docs.iroh.computer/connecting/gossip This command adds the iroh-gossip crate to your Rust project's dependencies. Ensure you have Cargo installed and are in your project's root directory. ```rust cargo add iroh-gossip ``` -------------------------------- ### Initialize Rust Project with Iroh Dependencies Source: https://docs.iroh.computer/examples/chat Sets up a new Rust project and adds necessary Iroh and utility dependencies like tokio, anyhow, and rand for async operations, error handling, and randomness. ```bash cargo init iroh-gossip-chat cd iroh-gossip-chat # Initial project setup # cargo run # Add dependencies cargo add iroh tokio anyhow rand cargo add iroh-gossip ``` -------------------------------- ### Rust Cross-Process Get Request with Postcard Source: https://docs.iroh.computer/protocols/rpc Demonstrates a Rust function for making a cross-process `Get` request using the `postcard` library for serialization. It opens a bi-directional connection, sends the serialized request, and deserializes the response. ```rust async fn get_remote(connection: Connection, key: String) -> Result> { let (send, recv) = connection.open_bi().await?; send.write_all(postcard::to_stdvec(GetRequest { key })?).await?; let res = recv.read_to_end(1024).await?; let res = postcard::from_bytes(&res)?; Ok(res) } ``` -------------------------------- ### QUIC Connection Stream Management (Rust) Source: https://docs.iroh.computer/protocols/using-quic Demonstrates how to open and accept uni-directional and bi-directional streams on a QUIC connection. These methods are crucial for establishing communication channels within a QUIC connection. ```rust impl Connection { async fn open_uni(&self) -> Result; async fn accept_uni(&self) -> Result, ConnectionError>; async fn open_bi(&self) -> Result<(SendStream, RecvStream), ConnectionError>; async fn accept_bi(&self) -> Result, ConnectionError>; } ``` -------------------------------- ### Iroh RPC Client for Key-Value Service in Rust Source: https://docs.iroh.computer/protocols/rpc This Rust code shows a client implementation for the Key-Value service using the `irpc` crate. The `Client` struct wraps an `irpc::Client` instance. The `get` method demonstrates how to make a remote RPC call for the 'Get' request, returning the result directly. ```rust struct Client(irpc::Client); impl Client { async fn get(&self, key: String) -> Result> { Ok(self.0.rpc(GetRequest { key }).await?) } } ``` -------------------------------- ### Create and Print Endpoint Ticket in Rust Source: https://docs.iroh.computer/quickstart Demonstrates how to create an `EndpointTicket` from an endpoint's address and print it for sharing. This ticket encapsulates the necessary information for other iroh endpoints to connect. ```rust use iroh_tickets::{Ticket, endpoint::EndpointTicket}; let ticket = EndpointTicket::new(endpoint.addr()); println!("{}", ticket); ``` -------------------------------- ### Set up iroh-blobs Router Source: https://docs.iroh.computer/protocols/blobs This Rust code snippet illustrates how to set up a router for handling incoming iroh-blobs connections. It uses `Router::builder` to create a router associated with the provided `endpoint`. The `.accept()` method is used to register a handler for the `iroh_blobs::ALPN` protocol, ensuring that incoming blob connections are routed correctly. The router is then spawned to run in the background. ```rust // For sending files we build a router that accepts blobs connections & routes them // to the blobs protocol. let router = Router::builder(endpoint) .accept(iroh_blobs::ALPN, blobs) .spawn(); tokio::signal::ctrl_c().await?; // Gracefully shut down the endpoint println!("Shutting down."); router.shutdown().await?; ``` -------------------------------- ### Multiplexing Requests & Responses with Rust Source: https://docs.iroh.computer/protocols/using-quic Illustrates how to multiplex multiple requests and responses over a single QUIC connection, similar to HTTP/3. This allows concurrent handling of requests without blocking. The connecting endpoint initiates requests, and the accepting endpoint handles them in separate tasks. This uses `iroh-net` and `tokio`. ```rust // The connecting endpoint can call this multiple times // for one connection. // When it doesn't want to do more requests and has all // responses, it can close the connection. async fn request(conn: &Connection, request: &[u8]) -> Result> { let (mut send, mut recv) = conn.open_bi().await?; send.write_all(request).await?; send.finish()?; let response = recv.read_to_end(MAX_RESPONSE_SIZE).await?; Ok(response) } // The accepting endpoint will call this to handle all // incoming requests on a single connection. async fn handle_requests(conn: Connection) -> Result<()> { loop { let stream = conn.accept_bi().await?; match stream { Some((send, recv)) => { tokio::spawn(handle_request(send, recv)); } None => break, // connection closed } } Ok(()) } async fn handle_request(mut send: SendStream, mut recv: RecvStream) -> Result<()> { let request = recv.read_to_end(MAX_REQUEST_SIZE).await?; let response = compute_response(&request); send.write_all(&response).await?; send.finish()?; Ok(()) } ``` -------------------------------- ### Run Iroh Automerge Endpoint (First Terminal) Source: https://docs.iroh.computer/protocols/automerge Starts the first iroh endpoint, which will listen for synchronization requests. It outputs a unique Endpoint ID that can be shared to establish connections. ```bash # First Terminal > cargo run Running Endpoint Id: lkpz2uw6jf7qahl7oo6qc46qad5ysszhtdzqyotkb3pwtd7sv3va ``` -------------------------------- ### Install iroh-blobs Crate Source: https://docs.iroh.computer/protocols/blobs Adds the iroh-blobs crate to a Rust project's dependencies using Cargo. This is the first step to using the library's features. ```bash cargo add iroh-blobs ``` -------------------------------- ### Rust Async Key-Value Store Request Enum Source: https://docs.iroh.computer/protocols/rpc Defines the message enum for a simple asynchronous key-value store, supporting Set and Get requests. Each variant includes necessary data and a oneshot channel for responses. ```rust enum Request { Set { key: String, value: String, response: oneshot::Sender<()> } Get { key: String, response: oneshot::Sender> } } ``` -------------------------------- ### Run Iroh Automerge Endpoint (Second Terminal) and Connect Source: https://docs.iroh.computer/protocols/automerge Starts a second iroh endpoint and connects it to the first endpoint using its provided Endpoint ID. This initiates the data synchronization process. ```bash # Second Terminal > cargo run -- --remote-id lkpz2uw6jf7qahl7oo6qc46qad5ysszhtdzqyotkb3pwtd7sv3va Running Endpoint Id: gcq5e7mcsvwgtxfvbu7w7rkikxhfudbqt5yvl34f47qlmsyuy7wa > ``` -------------------------------- ### Create an iroh Endpoint in Rust Source: https://docs.iroh.computer/quickstart Demonstrates how to create an iroh `Endpoint` in Rust. The endpoint manages network connections and allows devices to be addressed by their `EndpointId`. It's the foundation for P2P communication. ```rust use iroh::Endpoint; #[tokio::main] async fn main() -> anyhow::Result<()> { // Create an endpoint, it allows creating and accepting // connections in the iroh p2p world let endpoint = Endpoint::bind().await?; // ... Ok(()) } ``` -------------------------------- ### Rust Async Request Enum with Stream Support Source: https://docs.iroh.computer/protocols/rpc Extends the Rust request enum to include more complex operations like setting a value from a stream and getting a value as a stream. These variants utilize mpsc channels for streaming data. ```rust enum Request { ... SetFromStream { key: String, value: mpsc::Receiver, response: oneshot::Sender<()> } ... } enum Request { ... GetAsStream { key: String, response: mpsc::Sender> } ... } ``` -------------------------------- ### Receive File Using iroh-blobs CLI Source: https://docs.iroh.computer/protocols/blobs Example command to receive a file using the iroh-blobs CLI, identified by its content hash ('blobabvojvy[...]'). It shows the download and copy process. ```sh $ cargo run -- receive blobabvojvy[...] file.txt Starting download. Finished download. Copying to destination. Finished copying. Shutting down. ``` -------------------------------- ### Main Function: Parse Arguments and Run Role in Rust Source: https://docs.iroh.computer/quickstart The main entry point of the application, responsible for parsing command-line arguments to determine whether to run as a 'receiver' or 'sender'. It handles ticket deserialization for the sender role. ```rust // filepath: src/main.rs #[tokio::main] async fn main() -> Result<()> { let mut args = env::args().skip(1); let role = args .next() .ok_or_else(|| anyhow!("expected 'receiver' or 'sender' as the first argument"))?; match role.as_str() { "receiver" => run_receiver().await, "sender" => { let ticket_str = args .next() .ok_or_else(|| anyhow!("expected ticket as the second argument"))?; let ticket = EndpointTicket::deserialize(&ticket_str) .map_err(|e| anyhow!("failed to parse ticket: {}", e))?; run_sender(ticket).await } _ => Err(anyhow!("unknown role '{}'; use 'receiver' or 'sender'", role)), } } ``` -------------------------------- ### Send File Using iroh-blobs CLI Source: https://docs.iroh.computer/protocols/blobs Example command to send a local file ('./file.txt') using the iroh-blobs CLI. It shows the output indicating the file has been indexed and provides a command to receive it. ```sh $ cargo run -- send ./file.txt Indexing file. File analyzed. Fetch this file by running: cargo run -- receive blobabvojvy[...] file.txt ``` -------------------------------- ### Rust: Implement Connecting Side of QUIC Protocol Source: https://docs.iroh.computer/protocols/writing-a-protocol Implements the connecting side of a QUIC protocol using Rust. It establishes a connection to an accepting endpoint, opens a bidirectional stream, sends data, receives an echoed response, and gracefully closes the connection. Requires the `iroh-net` and `tokio` crates. ```rust async fn connect_side(addr: EndpointAddr) -> Result<()> { let endpoint = Endpoint::bind().await?; // Open a connection to the accepting endpoint let conn = endpoint.connect(addr, ALPN).await?; // Open a bidirectional QUIC stream let (mut send, mut recv) = conn.open_bi().await?; // Send some data to be echoed send.write_all(b"Hello, world!").await?; // Signal the end of data for this particular stream send.finish()?; // Receive the echo, but limit reading up to maximum 1000 bytes let response = recv.read_to_end(1000).await?; assert_eq!(&response, b"Hello, world!"); // Explicitly close the whole connection. conn.close(0u32.into(), b"bye!"); // The above call only queues a close message to be sent (see how it's not async!). // We need to actually call this to make sure this message is sent out. endpoint.close().await; // If we don't call this, but continue using the endpoint, we then the queued // close call will eventually be picked up and sent. // But always try to wait for endpoint.close().await to go through before dropping // the endpoint to ensure any queued messages are sent through and connections are // closed gracefully. Ok(()) } ``` -------------------------------- ### Rust: Accept Bi-directional Stream and Send Response (0.5-RTT) Source: https://docs.iroh.computer/protocols/using-quic Demonstrates accepting a bi-directional stream on a QUIC connection and immediately writing a response. This utilizes the 0.5-RTT feature, allowing data to be sent before the client's handshake is fully completed. It reads the request, computes a response, and sends it back. ```rust async fn accepting_endpoint(conn: Connection) -> Result<()> { let (mut send, mut recv) = conn.accept_bi().await?.ok_or_else(|| anyhow!("connection closed"))?; let request = recv.read_to_end(MAX_REQUEST_SIZE).await?; // We can start sending the response immediately without waiting // for the client to finish the handshake let response = compute_response(&request); send.write_all(&response).await?; send.finish()?; conn.closed().await; Ok(()) } ```