# /command/{channel}

> Kind 10: a command the proxy asks the caller to run, its bytes opaque; the server sends one message per item the command produces, an error as the last message when there is one, and closes the connection; the proxy repeats no command.

Canonical: https://provider.diverge.network/2.3.0/proxy/command/
Specification revision: 2.3.0

The ask is kind `10` on [`/requests`](/2.3.0/proxy/requests/):

```text
[10][command …]
```

The command is bytes running to the end of the message. Neither the
proxy nor the server reads them. The server answers on
`/command/{channel}` by sending one message per item the command
produces, and closing the connection. Each message is the frame
defined below: a first byte of `0` is followed by the bytes of the
item; a first byte of `1` is followed by an error as JSON, and such a
message is the last the server sends.

- **The end of the command.** The server sends each item as the
  command produces it. The close, or the error, states that no
  further item follows. A path that the proxy or the server closes cleanly with no message
before the close states that the ask was not served.
- **No repetition.** The proxy does not ask a command again. A
  command whose path ended abruptly, and a command whose `/requests`
  connection ended before the server opened its path, have an
  outcome the proxy cannot know, and the proxy reports such a
  command inside the container as failed.

The ask is defined by `diverge-provider-sdk/src/shared/containers/command/request/request.rs`:

```rust
//! The command, as the container asks it.

use std::convert::Infallible;

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

/// A diverge command: bytes in the CLI's own vocabulary, which this
/// layer never reads. The whole payload after whatever tag or kind
/// names the ask.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Request<'a>(
    /// The command, verbatim.
    pub &'a [u8],
);

impl Encode for Request<'_> {
    /// [`Infallible`]: bytes copied.
    type Error = Infallible;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Infallible> {
        out.extend_from_slice(self.0);
        Ok(())
    }
}

impl<'a> Decode<'a> for Request<'a> {
    /// [`Infallible`]: the bytes are the command.
    type Error = Infallible;

    fn decode(bytes: &'a [u8]) -> Result<Self, Infallible> {
        Ok(Request(bytes))
    }
}
```

The messages are defined by `diverge-provider-sdk/src/shared/containers/command/response/frame.rs`:

```rust
//! One item the command produced, or the news that it will not
//! produce another.

use super::FrameError;
use crate::decode::Decode as _;
use crate::encode::{Encode, Writer};
use crate::shared::error::Error;

/// One item, or the end of them.
///
/// A message leads with one byte saying which — `0` for
/// [`Item`](Self::Item), `1` for [`Error`](Self::Error) — and the
/// rest is that variant's own bytes.
///
/// # An error is not an item
///
/// And the tag is what keeps them apart. Without it a command that
/// failed would have to say so IN an item, in whatever shape the CLI
/// used for that, and a container that did not know the shape could
/// not find out. [`Error`](Self::Error) is the caller saying the
/// command did not finish. What arrived before it is what the
/// command produced; nothing follows it, because the finish comes
/// after.
///
/// # The item is opaque, and the tag does not change that
///
/// The tag says whether there is an item, not what is in one.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame<'a> {
    /// One item, borrowed from the message it arrived in. Tag `0`.
    Item(&'a [u8]),
    /// The command did not finish. Tag `1`.
    ///
    /// See [`shared::error::Error`](crate::shared::error::Error) for
    /// why it says so little.
    Error(Error),
}

/// Tag for [`Frame::Item`].
const ITEM: u8 = 0;

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

impl Encode for Frame<'_> {
    /// The ordinary JSON failure, from the only variant that has one.
    /// An item is bytes copied.
    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::Item(item) => {
                out.extend_from_slice(&[ITEM]);
                out.extend_from_slice(item);
                Ok(())
            }
            Frame::Error(error) => {
                out.extend_from_slice(&[ERROR]);
                error.encode(out)
            }
        }
    }
}

impl<'a> Frame<'a> {
    /// Decode one message. An item borrows from `bytes`.
    pub fn decode(bytes: &'a [u8]) -> Result<Self, FrameError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
        match *tag {
            ITEM => Ok(Frame::Item(rest)),
            ERROR => Error::decode(rest)
                .map(super::Frame::Error)
                .map_err(FrameError::Error),
            tag => Err(FrameError::UnknownTag(tag)),
        }
    }
}
```

The ways in which a message fails to decode are defined by
`diverge-provider-sdk/src/shared/containers/command/response/error.rs`:

```rust
//! Why a command answer could not be decoded.

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

/// A command response that could not be read.
#[derive(Debug)]
pub enum FrameError {
    /// No bytes at all, so not even a tag.
    ///
    /// Distinct from an empty item, which is a tag byte followed by
    /// nothing and is a command that produced something with no bytes
    /// in it.
    Empty,
    /// A tag that is neither of this response's two.
    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("command response is empty")
            }
            FrameError::UnknownTag(tag) => {
                write!(f, "unknown command response tag {tag}")
            }
            FrameError::Error(error) => {
                write!(f, "command error did not parse: {error}")
            }
        }
    }
}

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