# Response

> The server sends exactly one response, whose payload is exactly the byte 0 when the file is at the path; exactly the byte 1, 2 or 3 when a running container, a FUSE serve or an operation holds the volume; exactly the byte 4 when the server keeps no volume; or the byte 5 followed by an error as one JSON value; once the content channel has finished or the write has failed, or before the content is asked for; and the response finish follows it.

Canonical: https://protocol.diverge.network/2.3.0/endpoints/volumes-write/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]                  written: the file is at the path
[1]                  not written: a running container holds the volume
[2]                  not written: a FUSE serve holds the volume
[3]                  not written: another operation holds the volume
[4]                  not written: the server keeps no volume
[5][error JSON …]    not written, and nothing partial is
```

- **The sequence.** Exactly one response precedes the response
  finish, and nothing follows the finish. The byte `0` is sent only
  once the content channel has finished; a refusal is sent before the
  content channel is opened; an error is sent before the content
  channel is opened, or once the write has failed. A response finish
  that no response precedes states that the request was not served,
  as [Endpoints](/2.3.0/endpoints/) provides.
- **Written.** A payload whose first byte is `0` states that the file
  is at the path, whole. The server sends nothing after the byte `0`,
  and a client ignores every byte that follows it.
- **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
  nothing was written, that the content was not asked for, and that
  the destination is as it was. 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/), another
  `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
  states that the file is not at the path as a result of the request,
  that nothing partial is, and that the destination is as it was
  before the request.
- **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/write/server/response/frame.rs`:

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

use std::fmt;

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

/// The file landed, or it did not.
///
/// A payload leads with one byte saying which — `0` for
/// [`Written`](Self::Written), `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 |
/// |---------------------|-------|
/// | a [`Written`](Self::Written), then a finish | the file is at the path |
/// | [`Mounted`](Self::Mounted), then a finish | a running container has the volume, and nothing was written |
/// | [`FuseServed`](Self::FuseServed), then a finish | a FUSE serve holds the volume, and nothing was written |
/// | [`Held`](Self::Held), then a finish | another operation has the volume to itself, and nothing was written |
/// | an [`Error`](Self::Error), then a finish | it is not, and nothing partial is |
///
/// Only a finish ends it, and it comes only once the content channel
/// has — or at once, for a write refused before the content was asked
/// for: a volume the caller cannot see, one that something holds, a
/// parent that is not a directory.
///
/// # 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 answer is not
///
/// [`Written`](Self::Written) carries
/// [`write_path::response::Frame`](crate::shared::containers::write_path::response::Frame),
/// which means the same thing wherever the exchange happens. The
/// [`Error`](Self::Error) beside it is the exchange's own.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
    /// The file is at the path. Tag `0`.
    Written(write_path::response::Frame),
    /// The volume is mounted in a running container, and was not
    /// written. Tag `1`.
    ///
    /// Nothing was changed; a caller stops the container and asks
    /// again.
    Mounted,
    /// A FUSE serve holds the volume, and it was not written.
    /// 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
    /// written. 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::Written`].
const WRITTEN: 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::Written(inner) => {
                out.extend_from_slice(&[WRITTEN]);
                // 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 Decode<'_> for Frame {
    /// 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: &[u8]) -> Result<Self, FrameError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
        match *tag {
            WRITTEN => write_path::response::Frame::decode(rest)
                .map(Frame::Written)
                .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 write response frame that could not be read.
#[derive(Debug)]
pub enum FrameError {
    /// No bytes at all, so not even a tag.
    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 write response frame is empty")
            }
            FrameError::UnknownTag(tag) => {
                write!(f, "unknown volume write response frame tag {tag}")
            }
            FrameError::Error(error) => {
                write!(f, "volume write 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,
        }
    }
}
```
