> ## Documentation Index
> Fetch the complete documentation index at: https://hayate.shiina.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# HayateReceiver: Accept File Transfers in Your Rust App

> HayateReceiver binds a QUIC listener to accept incoming file or directory transfers. Configure bind address, pairing code, and consent behavior.

`HayateReceiver` is the high-level interface for accepting incoming encrypted file and directory transfers. Like `HayateSender`, it follows a builder pattern — configure it with chained calls, then invoke `.receive()` to bind a QUIC listener, wait for an incoming connection, perform the handshake, and save the payload to disk. The receiver supports both Direct Mode (wait for a connection on a known port) and Pairing Mode (find the sender by listening for a matching LAN broadcast).

## Builder Methods

<ParamField path="HayateReceiver::new()" type="HayateReceiver">
  Creates a new `HayateReceiver` with default configuration. Defaults: bind address `0.0.0.0:50001`, no pairing code, auto-accept disabled.
</ParamField>

<ParamField path=".bind(addr: SocketAddr)" type="HayateReceiver">
  Sets the local socket address the QUIC listener will bind to. Use this to control which network interface and port Hayate listens on. Defaults to `0.0.0.0:50001` if not called.
</ParamField>

<ParamField path=".code(phrase: String)" type="HayateReceiver">
  Sets the shared passphrase for **Pairing Mode**. The receiver will listen for UDP broadcast and mDNS announcements whose channel ID matches a hash of this phrase, then connect to the sender automatically. The passphrase is mixed into key derivation — only a sender that knows the same phrase can complete the handshake.
</ParamField>

<ParamField path=".auto_accept(accept: bool)" type="HayateReceiver">
  When set to `true`, the receiver accepts every incoming transfer without invoking the `consent_cb`. Default: `false`. Useful for automated pipelines where every incoming transfer is trusted, but should not be used in interactive applications where the user should approve transfers.
</ParamField>

## Receiving

```rust theme={null}
pub async fn receive(
    self,
    output_dir: impl AsRef<Path>,
    consent_cb: impl FnOnce(&Metadata) -> bool,
    progress_cb: impl FnMut(u64) -> Result<(), EngineError> + Send + 'static,
) -> Result<(String, PathBuf), EngineError>
```

Binds the QUIC endpoint, waits for one incoming connection, performs the handshake, invokes the consent callback, and if accepted, receives the payload and writes it to `output_dir`. Returns `(checksum, saved_path)` on success.

* **`output_dir`** — the directory where the received file or directory will be written. The final filename comes from the `Metadata` transmitted by the sender.
* **`consent_cb: impl FnOnce(&Metadata) -> bool`** — called once after the handshake, with the decrypted `Metadata` describing the incoming transfer (filename, size, hash algorithm). Return `true` to accept the transfer, `false` to reject it. If `.auto_accept(true)` was set, this callback is not invoked.
* **`progress_cb`** — called periodically with the total number of bytes received so far. Return `Ok(())` to continue; return `Err(EngineError::Cancelled(...))` to abort.

The return value is a `(String, PathBuf)` tuple: the hex checksum of the received payload, and the full filesystem path where it was saved.

## Complete Examples

<CodeGroup>
  ```rust Pairing Mode theme={null}
  use hayate::HayateReceiver;

  #[compio::main]
  async fn main() -> Result<(), hayate::EngineError> {
      let receiver = HayateReceiver::new()
          .code("apple-bravo-charlie".to_owned())
          .auto_accept(true);

      let (checksum, path) = receiver.receive(
          "./downloads",
          |_meta| true,  // auto-accept
          |bytes| {
              println!("Received {bytes} bytes");
              Ok(())
          },
      ).await?;

      println!("Saved to: {}", path.display());
      println!("Checksum: {checksum}");
      Ok(())
  }
  ```

  ```rust Direct Mode with consent check theme={null}
  use std::net::SocketAddr;
  use hayate::HayateReceiver;

  #[compio::main]
  async fn main() -> Result<(), hayate::EngineError> {
      let bind_addr: SocketAddr = "0.0.0.0:50001".parse().unwrap();

      let receiver = HayateReceiver::new()
          .bind(bind_addr);

      let (checksum, path) = receiver.receive(
          "./downloads",
          |meta| {
              println!("Incoming: {} ({} bytes)", meta.filename, meta.total_size);
              // Accept only files under 100 MB
              meta.total_size < 100 * 1024 * 1024
          },
          |bytes| {
              println!("Progress: {bytes} bytes");
              Ok(())
          },
      ).await?;

      println!("Saved to: {}", path.display());
      Ok(())
  }
  ```
</CodeGroup>

<Tip>
  The `consent_cb` gives you access to the full `Metadata` struct before any payload bytes are written to disk. You can use it to enforce file size limits, check the filename against an allowlist, inspect the hash algorithm, or prompt the user for confirmation — and return `false` to cleanly reject the transfer without downloading any data.
</Tip>
