# Response

> The server sends exactly one response, whose payload begins with the byte 0 followed by the tree in the postcard wire format, a varint count of nodes followed by that many nodes; is the byte 1, 2 or 3 alone when a running container, a FUSE serve or an operation holds the volume; is the byte 4 alone when the server keeps no volume; or begins with the byte 5 followed by an error as one JSON value; and the response finish follows it.

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

The server sends exactly one response on the scope. The response
finish follows the response, and no frame follows the finish.

```text
[0][tree, postcard …]    the tree
[1]                      not walked: a running container holds the volume
[2]                      not walked: a FUSE serve holds the volume
[3]                      not walked: another operation holds the volume
[4]                      not walked: the server keeps no volume
[5][error JSON …]        not walked
```

- **The sequence.** Exactly one response precedes the response
  finish, and nothing follows the finish. A response finish that no
  response precedes states that the request was not served, as
  [Endpoints](/2.3.0/endpoints/) provides.
- **The tree.** A payload whose first byte is `0` carries the tree
  after that byte, running to the end of the payload: a varint count
  followed by that many nodes, in the encoding the postcard reading
  of [Notation](/2.3.0/endpoints/#notation) provides. A node is one of the
  three variants the
  [filetree](/2.3.0/endpoints/containers-agents-run/client/filetree/response/)
  channel defines, `File`, `Directory` or `Symlink`, in the form that
  page states, with these determinations. Every `Directory` has
  `changes` `0`: nothing watches the volume, and no change is sent. A
  `Symlink` is the link itself, never followed, and its `path` is the
  target of the link as components relative to the root of the
  volume. `created_at` and `modified_at` are what the volume records,
  absent where it records none. The count `0` is an empty directory,
  and the payload is exactly the one byte `0`.
- **Paths.** Every `name` is the name of a node in its directory. The
  directory the request named has no node of its own: the tree
  carries its entries.
- **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. On
  a server that keeps no volume, the byte `4` is the only response,
  sent before anything is looked up. Every refusal states that the
  tree was not sent 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/),
  a [volumes::read](/2.3.0/endpoints/volumes-read/), a
  [volumes::write](/2.3.0/endpoints/volumes-write/), another
  `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.
- **Malformed.** A payload with no byte, a payload whose first byte
  is none of `0` to `5`, a payload whose bytes after `0` do not
  decode as the tree, 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/filetree/server/response/frame.rs`:

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

use std::fmt;

use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::error::Error;
use crate::shared::filetree::response::Node;

/// The tree, or the news that it could not be walked.
///
/// One of these on channel `0`, then the scope finishes. A payload
/// leads with one byte saying which — `0` for [`Tree`](Self::Tree),
/// `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.
///
/// # 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.
///
///
/// A filetree here is not a stream: a provider walks the subtree once
/// and says what it found, so there is nothing to discover
/// incrementally and nothing to hold a channel open for. The tree is
/// what a [`Snapshot`](crate::shared::filetree::response::Frame::Snapshot)
/// carries, the entries of the subtree the request named, as
/// [`Node`]s — the same nodes a container's live filetree sends, with
/// every directory's `changes` false, since nothing watches.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
    /// The tree. Tag `0`.
    Tree(Vec<Node>),
    /// The volume is mounted in a running container, and was not
    /// walked. Tag `1`.
    ///
    /// Nothing was changed; a caller stops the container and asks
    /// again.
    Mounted,
    /// A FUSE serve holds the volume, and it was not walked.
    /// 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
    /// walked. 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`.
    ///
    /// A volume the caller cannot see is one, and so is a path that
    /// names no directory, and a walk the provider could not finish. See
    /// [`shared::error::Error`](crate::shared::error::Error) for why
    /// it says so little.
    Error(Error),
}

/// Tag for [`Frame::Tree`].
const TREE: 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;

/// Two variants, two formats, and the tag chooses between them.
///
/// The tree is **postcard**, as every filetree frame is: the nodes are
/// the same type a container's live filetree sends, and they are
/// written the same way.
///
/// The error is JSON, and has to be. A
/// [`serde_json::Value`] deserializes through `deserialize_any`, which
/// a format with no self-description cannot answer — so postcard can
/// carry the tree and cannot carry the failure, and each variant gets
/// the format it needs.
impl Encode for Frame {
    /// One failure per half, and they are different libraries'.
    type Error = FrameEncodeError;

    // 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<(), FrameEncodeError> {
        match self {
            Frame::Tree(tree) => {
                out.extend_from_slice(&[TREE]);
                postcard::to_io(tree, &mut *out)
                    .map(|_| ())
                    .map_err(FrameEncodeError::Tree)
            }
            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).map_err(FrameEncodeError::Error)
            }
        }
    }
}

impl Decode<'_> for Frame {
    /// Four ways to fail, and each names which half failed.
    type Error = FrameDecodeError;

    // Spelled out for the same reason as `encode` above.
    fn decode(bytes: &[u8]) -> Result<Self, FrameDecodeError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameDecodeError::Empty)?;
        match *tag {
            TREE => postcard::from_bytes(rest)
                .map(Frame::Tree)
                .map_err(FrameDecodeError::Tree),
            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(FrameDecodeError::Error),
            tag => Err(FrameDecodeError::UnknownTag(tag)),
        }
    }
}

/// A volume filetree that could not be written.
#[derive(Debug)]
pub enum FrameEncodeError {
    /// The tree did not serialize.
    Tree(postcard::Error),
    /// The error did not serialize.
    Error(serde_json::Error),
}

impl fmt::Display for FrameEncodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FrameEncodeError::Tree(error) => {
                write!(f, "volume filetree did not serialize: {error}")
            }
            FrameEncodeError::Error(error) => {
                write!(f, "volume filetree error did not serialize: {error}")
            }
        }
    }
}

impl std::error::Error for FrameEncodeError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            FrameEncodeError::Tree(error) => Some(error),
            FrameEncodeError::Error(error) => Some(error),
        }
    }
}

/// A volume filetree that could not be read.
#[derive(Debug)]
pub enum FrameDecodeError {
    /// No bytes at all, so not even a tag.
    Empty,
    /// A tag that is none of this frame's six.
    UnknownTag(u8),
    /// The tree did not parse.
    Tree(postcard::Error),
    /// The error did not parse.
    Error(serde_json::Error),
}

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

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