# Request

> The payload of the channel request: the tag byte 1 and the request of the channel.

Canonical: https://protocol.diverge.network/2.3.0/endpoints/volumes-fuse-serve/client/write/request/
Specification revision: 2.3.0

```text
[1][path_len: u16, big-endian][path …][offset: u64, big-endian][bytes …]
```

- **The form.** The bytes after the tag are exactly the bytes after
  the tag of the [FUSE write](/2.3.0/container-proxy-endpoints/fuse-mount/server/write/request/) ask on a
  mount scope, and mean the same; that page states every field. The
  path is UTF-8, `/`-separated, with no leading `/`; empty is the
  root of the volume.
- **Malformed.** A channel request whose payload does not decode as
  stated is answered by a channel response finish that no channel
  response precedes, and the server does nothing else for it.

The channel request is defined by `diverge-sdk-rs/src/provider/endpoints/volumes/fuse_serve/client/channel_request/frame.rs`:

```rust
//! What a client's channel request frame carries on a FUSE serve scope.

use std::fmt;

use crate::container_proxy::outside::endpoints::fuse::mount::server::channel_request as mount;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};

/// What a client asks the provider for while a volume is served: one
/// of the nine asks, the stop, or the tree.
///
/// A payload leads with one byte saying which. The nine asks carry
/// the tags they carry on a mount's scope — `0` read, `1` write, `2`
/// list, `3` remove, `4` rename, `5` mkdir, `6` stat, `7` truncate,
/// `8` setattr — and are that scope's very frames, so a bridge
/// forwards bytes; `9` is the stop, bare; `10` is the tree, bare.
///
/// | tag | asks for |
/// |-----|----------|
/// | `0`–`8` | [`Ask`](Self::Ask): the mount's ask of that tag |
/// | `9` | [`Stop`](Self::Stop) |
/// | `10` | [`Filetree`](Self::Filetree) |
#[derive(Debug, Clone, PartialEq)]
pub enum Frame<'a> {
    /// One of the nine, answered on its channel with that ask's own
    /// frame — the shared vocabulary's — and the finish. The provider
    /// answers as a caller's server would, from the volume.
    Ask(mount::Frame<'a>),
    /// Stop serving. Tag `9`.
    ///
    /// Carries nothing, and nothing comes back on this channel: the
    /// provider sends no channel response and no channel response
    /// finish on it. What comes back is the scope's finish, after
    /// every ask still being answered has been: the provider gives
    /// the volume back and finishes. A second stop changes nothing.
    Stop,
    /// The tree of the volume as this FUSE serve sees it, and then every
    /// change to it. Tag `10`.
    ///
    /// Carries nothing: the scope is the volume, and the root is the
    /// volume's. Answered on its channel with a
    /// [`filetree`](crate::shared::filetree) stream — one snapshot of
    /// the served view, the FUSE serve's layer included, then one frame
    /// per change the FUSE serve's own asks make — for as long as the
    /// scope lives; the channel finishes with the scope. A read-only
    /// volume's stream is its snapshot and nothing after. Any number
    /// of these may be open at once, each a stream of its own
    /// beginning whole.
    Filetree,
}

/// Tag for [`Frame::Stop`].
const STOP: u8 = 9;

/// Tag for [`Frame::Filetree`].
const FILETREE: u8 = 10;

impl Encode for Frame<'_> {
    /// The ask's own failure; the stop and the tree cannot fail.
    type Error = mount::FrameEncodeError;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Self::Error> {
        match self {
            Frame::Ask(ask) => ask.encode(out),
            Frame::Stop => {
                out.extend_from_slice(&[STOP]);
                Ok(())
            }
            Frame::Filetree => {
                out.extend_from_slice(&[FILETREE]);
                Ok(())
            }
        }
    }
}

impl<'a> Decode<'a> for Frame<'a> {
    /// The ask's own failures, and the empty payload.
    type Error = FrameError;

    fn decode(bytes: &'a [u8]) -> Result<Self, Self::Error> {
        match bytes.first() {
            None => Err(FrameError::Empty),
            Some(&STOP) => Ok(Frame::Stop),
            Some(&FILETREE) => Ok(Frame::Filetree),
            Some(_) => mount::Frame::decode(bytes).map(Frame::Ask).map_err(FrameError::Ask),
        }
    }
}

/// A FUSE serve channel request that could not be read.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FrameError {
    /// No bytes at all, so not even a tag.
    Empty,
    /// The ask did not decode: an unknown tag, or fewer bytes than it
    /// promises.
    Ask(mount::FrameError),
}

impl fmt::Display for FrameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FrameError::Empty => f.write_str("volume FUSE serve channel request frame is empty"),
            FrameError::Ask(error) => write!(f, "volume FUSE serve ask did not decode: {error}"),
        }
    }
}

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

and by `diverge-sdk-rs/src/container_proxy/outside/endpoints/fuse/mount/server/channel_request/write.rs`:

```rust
//! Write a piece of a mounted file.

use std::str;

use super::{FrameEncodeError, FrameError, prefixed};
use crate::wire::encode::{Encode, Writer};

/// Write a piece of a file of the mount in place at `offset`, by its
/// path. Answered with one
/// [`Ack`](crate::shared::containers::fuse::ack::Frame).
///
/// ```text
/// [path_len: u16 BE][path: utf8…][offset: u64 BE][bytes…]
/// ```
///
/// The bytes follow the path, so the path carries a length prefix
/// here. On a file mount the path is empty. One `write(2)`, one ask:
/// a file that does not exist yet is made by this, one shorter than
/// the offset is extended to it, and the bytes at and after the
/// offset are replaced.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Write<'a> {
    /// The file's path inside the mount; empty for a file mount.
    pub path: &'a str,
    /// Where the piece lands, in bytes from the file's start.
    pub offset: u64,
    /// The piece, verbatim. Empty writes nothing and makes the file.
    pub bytes: &'a [u8],
}

impl Encode for Write<'_> {
    /// One way to fail: a path longer than its prefix holds.
    type Error = FrameEncodeError;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), FrameEncodeError> {
        prefixed::put(out, self.path.as_bytes())?;
        out.extend_from_slice(&self.offset.to_be_bytes());
        out.extend_from_slice(self.bytes);
        Ok(())
    }
}

impl<'a> Write<'a> {
    /// Decode from the bytes after the ask's tag. The path and the
    /// bytes borrow from `bytes`.
    pub fn decode(bytes: &'a [u8]) -> Result<Self, FrameError> {
        let (path, rest) = prefixed::take(bytes)?;
        let offset: [u8; 8] = rest.get(..8).and_then(|head| head.try_into().ok()).ok_or(FrameError::Truncated)?;
        Ok(Write {
            path: str::from_utf8(path).map_err(|_| FrameError::PathUtf8)?,
            offset: u64::from_be_bytes(offset),
            bytes: &rest[8..],
        })
    }
}
```
