# Response

> The server sends the bytes of the file as responses whose first byte is 0, each at most CHUNK_SIZE bytes, and the finish; a file of zero bytes is one empty response; the byte 1, 2 or 3 alone, when a running container, a FUSE serve or an operation holds the volume, or the byte 4 alone, when the server keeps no volume, is the only response; a response whose first byte is 5 carries an error and is the last.

Canonical: https://protocol.diverge.network/2.3.0/endpoints/volumes-read/response/
Specification revision: 2.3.0

```text
[0][bytes …]         a piece of the file
[1]                  not read: a running container holds the volume
[2]                  not read: a FUSE serve holds the volume
[3]                  not read: another operation holds the volume
[4]                  not read: the server keeps no volume
[5][error JSON …]    the file was not read, or not all of it
```

- **The sequence.** Zero or more responses whose first byte is `0`,
  each a piece of the file in order, followed by the response finish;
  or the responses sent so far, exactly one response whose first byte
  is `5`, and the response finish; or exactly one response whose
  payload is the byte `1`, `2`, `3` or `4` and nothing else, and the
  response finish. A file of zero bytes is exactly one response whose
  first byte is `0` and nothing after it. A response finish that no
  response precedes states that the request was not served, as
  [Endpoints](/2.3.0/endpoints/) provides.
- **The piece.** After the byte `0`, the bytes of the piece,
  verbatim, running to the end of the payload. Each piece is at most
  `CHUNK_SIZE` bytes, `2 * 1024 * 1024`, the constant
  `diverge-sdk-rs/src/lib.rs` defines; the pieces concatenated are the file, and a
  receiver measures none.
- **The refusals, and their order.** The server decides the bytes
  `1`, `2` and `3` in the order [Capabilities](/2.3.0/capabilities/#the-hold)
  states for an operation, the first rule that applies deciding, and
  sends the one that applies before any piece. On a server that
  keeps no volume, the byte `4` is the only response, sent before
  anything is looked up. Every refusal states that nothing was read
  and that nothing changed. A client ignores every byte that follows
  the byte `1`, `2`, `3` or `4`.
- **Mounted.** A payload that is the byte `1` and nothing else states
  that a running container of the client holds the volume at the
  time of the request.
- **FUSE served.** A payload that is the byte `2` and nothing else
  states that a [volumes::fuse_serve](/2.3.0/endpoints/volumes-fuse-serve/)
  of the client holds the volume at the time of the request.
- **Held.** A payload that is the byte `3` and nothing else states
  that the volume is under a [volumes::stat](/2.3.0/endpoints/volumes-stat/),
  another `volumes::read`, a
  [volumes::write](/2.3.0/endpoints/volumes-write/), a
  [volumes::filetree](/2.3.0/endpoints/volumes-filetree/), a
  [volumes::edit](/2.3.0/endpoints/volumes-edit/) or a
  [volumes::delete](/2.3.0/endpoints/volumes-delete/) at the time of the
  request.
- **Unsupported.** A payload that is the byte `4` and nothing else
  states that the server holds out none of the three mode objects
  and keeps no volume, as [Capabilities](/2.3.0/capabilities/#the-volume-modes)
  provides.
- **The error.** A payload whose first byte is `5` carries an error
  after that byte, running to the end of the payload. The error is
  exactly one JSON value, in the form defined on the
  [volumes::list response](/2.3.0/endpoints/volumes-list/response/) page.
  This revision prescribes nothing about its content. The error is
  the last response of the scope.
- **Malformed.** A payload with no byte, a payload whose first byte
  is none of `0` to `5`, and a payload whose bytes after `5` are not
  one JSON value are malformed.

The response is defined by `diverge-sdk-rs/src/provider/endpoints/volumes/read/server/response/frame.rs`:

```rust
//! What a server's response frame carries for a volume read.

use std::fmt;

use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::containers::read;
use crate::shared::error::Error;

/// A piece of the file, or the news that there will not be one.
///
/// A payload leads with one byte saying which — `0` for
/// [`Body`](Self::Body), `1` for [`Mounted`](Self::Mounted), `2` for
/// [`FuseServed`](Self::FuseServed), `3` for [`Held`](Self::Held),
/// `4` for [`Unsupported`](Self::Unsupported), `5` for
/// [`Error`](Self::Error) — and the rest is that variant's own bytes,
/// of which the four refusals have none.
///
/// # How it ends
///
/// | the scope ends with | means |
/// |---------------------|-------|
/// | bodies, then a finish | the bytes are the file |
/// | [`Mounted`](Self::Mounted), then a finish | a running container has the volume, and the file was not read |
/// | [`FuseServed`](Self::FuseServed), then a finish | a FUSE serve holds the volume, and the file was not read |
/// | [`Held`](Self::Held), then a finish | another operation has the volume to itself, and the file was not read |
/// | an [`Error`](Self::Error), then a finish | the file was not read, or not all of it |
///
/// Only a finish ends it. A zero-byte file is one empty body, then
/// the finish, so that a finish with nothing before it keeps its
/// standing meaning: could not serve, with nothing to say.
///
/// # Mounted, FUSE served and held are answers, not errors
///
/// A volume that something holds is not touched, and the provider
/// says which thing holds it — a running container, a FUSE serve, or
/// another operation — with its own variant rather than an
/// [`Error`](Self::Error) a caller could not tell from any other
/// failure. The distinction is what a caller acts on: stop the
/// container, stop the FUSE serve, or wait, and ask again.
///
/// # The failure is this scope's, the bytes are not
///
/// [`Body`](Self::Body) carries
/// [`read::response::Frame`](crate::shared::containers::read::response::Frame),
/// which means the same thing wherever the exchange happens — a piece
/// of a file, at most [`CHUNK_SIZE`](crate::CHUNK_SIZE), appended to
/// the pieces before it. The [`Error`](Self::Error) beside it is the
/// exchange's own: a volume the caller cannot see, a path that names
/// no file.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame<'a> {
    /// A piece of the file. Tag `0`.
    ///
    /// Each at most [`CHUNK_SIZE`](crate::CHUNK_SIZE), in order, and
    /// every one appends to the file.
    Body(read::response::Frame<'a>),
    /// The volume is mounted in a running container, and was not
    /// read. Tag `1`.
    ///
    /// Nothing was changed; a caller stops the container and asks
    /// again.
    Mounted,
    /// A FUSE serve holds the volume, and it was not read.
    /// Tag `2`.
    ///
    /// Nothing was changed; a caller stops the FUSE serve and asks
    /// again.
    FuseServed,
    /// Another operation — a stat, a read, a write, a filetree, an
    /// edit or a delete — has the volume to itself, and it was not
    /// read. Tag `3`.
    ///
    /// Nothing was changed; a caller waits for it to end and asks
    /// again.
    Held,
    /// The provider keeps no volumes: no mode is among its capabilities,
    /// see [`info`](crate::provider::endpoints::info), and every volume
    /// endpoint answers this. Tag `4`.
    ///
    /// Carries nothing. Nothing was looked at; a caller asks another
    /// provider.
    Unsupported,
    /// A failure. Tag `5`.
    ///
    /// See [`shared::error::Error`](crate::shared::error::Error) for
    /// why it says so little.
    Error(Error),
}

/// Tag for [`Frame::Body`].
const BODY: u8 = 0;

/// Tag for [`Frame::Mounted`].
const MOUNTED: u8 = 1;

/// Tag for [`Frame::FuseServed`].
const FUSE_SERVED: u8 = 2;

/// Tag for [`Frame::Held`].
const HELD: u8 = 3;

/// Tag for [`Frame::Unsupported`].
const UNSUPPORTED: u8 = 4;

/// Tag for [`Frame::Error`].
const ERROR: u8 = 5;

impl Encode for Frame<'_> {
    /// The ordinary JSON failure, from the half that has one. The
    /// other cannot fail.
    type Error = serde_json::Error;

    // Spelled out rather than `Self::Error`: this enum has a variant
    // called `Error`, so the associated type is ambiguous by that name.
    fn encode(
        &self,
        out: &mut Writer<'_>,
    ) -> Result<(), serde_json::Error> {
        match self {
            Frame::Body(inner) => {
                out.extend_from_slice(&[BODY]);
                // Its error is `Infallible`, and an empty match on one
                // is how you say so: there is no value to handle.
                inner.encode(out).map_err(|error| match error {})
            }
            Frame::Mounted => {
                out.extend_from_slice(&[MOUNTED]);
                Ok(())
            }
            Frame::FuseServed => {
                out.extend_from_slice(&[FUSE_SERVED]);
                Ok(())
            }
            Frame::Held => {
                out.extend_from_slice(&[HELD]);
                Ok(())
            }
            Frame::Unsupported => {
                out.extend_from_slice(&[UNSUPPORTED]);
                Ok(())
            }
            Frame::Error(error) => {
                out.extend_from_slice(&[ERROR]);
                error.encode(out)
            }
        }
    }
}

impl<'a> Decode<'a> for Frame<'a> {
    /// Three ways to fail, and only one of them is a parse.
    type Error = FrameError;

    // Spelled out for the same reason as `encode` above.
    fn decode(bytes: &'a [u8]) -> Result<Self, FrameError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
        match *tag {
            BODY => read::response::Frame::decode(rest)
                .map(Frame::Body)
                .map_err(|error| match error {}),
            MOUNTED => Ok(Frame::Mounted),
            FUSE_SERVED => Ok(Frame::FuseServed),
            HELD => Ok(Frame::Held),
            UNSUPPORTED => Ok(Frame::Unsupported),
            ERROR => {
                Error::decode(rest).map(Frame::Error).map_err(FrameError::Error)
            }
            tag => Err(FrameError::UnknownTag(tag)),
        }
    }
}

/// A volume read response frame that could not be read.
#[derive(Debug)]
pub enum FrameError {
    /// No bytes at all, so not even a tag.
    ///
    /// Distinct from a zero-length body, which is a tag followed by
    /// nothing and is a file.
    Empty,
    /// A tag that is none of this frame's six.
    UnknownTag(u8),
    /// The error did not parse.
    Error(serde_json::Error),
}

impl fmt::Display for FrameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FrameError::Empty => {
                f.write_str("volume read response frame is empty")
            }
            FrameError::UnknownTag(tag) => {
                write!(f, "unknown volume read response frame tag {tag}")
            }
            FrameError::Error(error) => {
                write!(f, "volume read error did not parse: {error}")
            }
        }
    }
}

impl std::error::Error for FrameError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            FrameError::Error(error) => Some(error),
            FrameError::Empty | FrameError::UnknownTag(_) => None,
        }
    }
}
```
