# Request

> The payload of the channel request the server sends: the write id, four bytes, with no tag.

Canonical: https://provider.diverge.network/2.3.0/endpoints/containers-tools-connect/server/write-bytes/request/
Specification revision: 2.3.0

```text
[write_id: u32, big-endian]
```

- **No tag.** The server opens one kind of channel on a connect
  scope, so its channel request carries no tag: the payload is the
  write id of the connector's write channel request, four bytes,
  big-endian.

The channel request is defined by `diverge-provider-sdk/src/endpoints/containers/tools/connect/server/channel_request/frame.rs`:

```rust
//! What a server's channel request frame carries for a tool container
//! connection.

use crate::decode::Decode;
use crate::encode::{Encode, Writer};
use crate::shared::containers::write_bytes;

/// Send the content for a write.
///
/// What a provider asks a connector for, and never unprompted. A
/// provider wants nothing from a connector on its own account — the
/// image was somebody else's problem, so is deciding who may attach,
/// and so are the container's own asks, which go to its runner. This
/// exists only because a write cannot carry its own content: only a
/// responder can finish a channel, so the bytes have to travel as
/// responses on a channel the provider opened.
///
/// # A struct, and no tag
///
/// One thing to ask for is a struct; an enum of one variant would be a
/// discriminant with nothing to discriminate — and a tag byte is that
/// discriminant written on the wire, so it goes for the same reason.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Frame(
    /// Which write, by the id the connector gave it.
    pub write_bytes::request::Request,
);

/// The write id's four bytes, and nothing in front of them.
impl Encode for Frame {
    /// [`Infallible`](std::convert::Infallible): four known bytes.
    type Error = std::convert::Infallible;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Self::Error> {
        self.0.encode(out)
    }
}

impl Decode<'_> for Frame {
    /// One way to fail: a payload that was not four bytes.
    type Error = write_bytes::request::RequestError;

    fn decode(bytes: &[u8]) -> Result<Self, Self::Error> {
        write_bytes::request::Request::decode(bytes).map(Frame)
    }
}
```

and by `diverge-provider-sdk/src/shared/containers/write_bytes/request/request.rs`:

```rust
//! The provider asking for a write's content.

use std::error::Error;
use std::fmt;

use crate::decode::Decode;
use crate::encode::{Encode, Writer};

/// Send the content for a write.
///
/// Opened by the provider, on its own channel, in answer to a
/// [`write_path::request::Request`](crate::shared::containers::write_path::request::Request)
/// the client opened on one of its.
///
/// # Why it names the write
///
/// Because a client may have several in flight, and this channel is
/// not the one the write arrived on — only a responder can finish a
/// channel, so the provider had to open one of its own to ask.
///
/// Neither side's header can name the other's channels: they are
/// numbered per SENDER, so a number in one namespace means nothing in
/// the other. The
/// [`write_id`](crate::shared::containers::write_path::request::Request::write_id)
/// belongs to the write instead of to either channel, which is what
/// lets both ends read it.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Request {
    /// The write being asked about, quoted from the
    /// [`write_path::request::Request`](crate::shared::containers::write_path::request::Request)
    /// that opened it.
    pub write_id: u32,
}

/// The bytes a write id occupies.
const WRITE_ID_LEN: usize = 4;

/// Four big-endian bytes. No serialization, because a fixed-width
/// integer does not need one.
impl Encode for Request {
    /// [`Infallible`](std::convert::Infallible): four known bytes.
    type Error = std::convert::Infallible;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Self::Error> {
        out.extend_from_slice(&self.write_id.to_be_bytes());
        Ok(())
    }
}

impl Decode<'_> for Request {
    /// One way to fail: the wrong number of bytes.
    type Error = RequestError;

    fn decode(bytes: &[u8]) -> Result<Self, Self::Error> {
        <[u8; WRITE_ID_LEN]>::try_from(bytes)
            .map(|bytes| Request {
                write_id: u32::from_be_bytes(bytes),
            })
            .map_err(|_| RequestError::Length(bytes.len()))
    }
}

/// A content request that could not be read.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RequestError {
    /// A payload that was not four bytes, carrying however many there
    /// were.
    Length(usize),
}

impl fmt::Display for RequestError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RequestError::Length(len) => {
                write!(f, "write content request is {len} bytes, not 4")
            }
        }
    }
}

impl Error for RequestError {}
```
