Response
The sequence of channel responses the server sends, what ends it, and what a finish with nothing before it means.
[0] the mount is made
[1] the path overlaps a mount the container holds
[2] the id is one the container holds a FUSE mount under
[3][error JSON …] the proxy did not make the mount
- The sequence. Exactly one channel response, followed by the
channel response finish. The server sends the byte
0or the byte3after the proxy has answered, and the byte1or2without asking the proxy. A channel response finish that no channel response precedes states that the request did not decode, or that the proxy’s connection ended before the proxy answered; nothing is mounted. - Mounted. The byte
0and nothing after it: the mount is serving at the path. Every ask of the id follows the channel response finish. - Overlaps. The byte
1and nothing after it: the path is a mount’s the container holds, lies inside one, or holds one — a volume mount’s or a FUSE mount’s, the request’s or one made since. Nothing is mounted. - Taken. The byte
2and nothing after it: the id is one the container holds a FUSE mount under. Nothing is mounted. - The error. After the byte
3, exactly one JSON value in the form defined on the volumes::list response page: the proxy’s refusal of the mount, in the proxy’s words. Nothing is mounted, and the id and the path are free.
The channel response is defined by diverge-sdk-rs/src/provider/endpoints/containers/agents/run/server/channel_response/fuse_mount/frame.rs:
//! What a server's response frame carries for a FUSE mount made while
//! the container runs.
/// `Mounted` once the mount is serving; `Overlaps`, `Taken` or
/// `Unsupported` for a request the provider refuses on its own
/// account, without asking the proxy; `Error` for one the proxy
/// refused, in its words — exactly one, then the finish, and a
/// `Mounted` before any ask of the id. See
/// [`fuse_mount::response::Frame`](crate::shared::containers::fuse_mount::response::Frame).
///
/// An alias rather than a re-export because this module is real: the
/// path says this channel's answer lives here, and it does, rather
/// than naming somewhere else and hoping a reader follows. What the
/// alias points at is right there in the signature.
pub type Frame = crate::shared::containers::fuse_mount::response::Frame;
and by diverge-sdk-rs/src/shared/containers/fuse_mount/response/frame.rs:
//! What a server's response frame carries for a FUSE mount made while a container runs.
use std::fmt;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::error::Error;
use serde::Serialize;
/// Whether the mount the caller asked for while the container runs
/// is made.
///
/// A payload leads with one byte saying which — `0` for
/// [`Mounted`](Self::Mounted), `1` for [`Overlaps`](Self::Overlaps),
/// `2` for [`Taken`](Self::Taken), `3` for [`Error`](Self::Error) —
/// and only the error carries anything after it.
///
/// # Exactly one, then the finish
///
/// The provider sends exactly one of these on the channel, after the
/// proxy has answered where the proxy was asked, and finishes the
/// channel. A [`Mounted`](Self::Mounted) precedes every ask the
/// provider relays for the mount's id. The mount lives until the run
/// ends, and nothing unmounts it. A finish that none of these
/// precedes is a request that did not decode.
///
/// # As JSON
///
/// For a client that prints what the provider answered: the variant,
/// snake case — `"mounted"`, `"overlaps"` — and the error over its
/// payload, `{"error":…}`. The wire is the tag byte and the payload,
/// never this.
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Frame {
/// The mount is made and serving at the path; every ask of the id
/// follows. Tag `0`.
Mounted,
/// The path is a mount's the container holds, lies inside one, or
/// holds one — a volume mount's or a FUSE mount's, the request's
/// or one made since; nothing is mounted. Tag `1`.
Overlaps,
/// The id is one the container holds a FUSE mount under; nothing
/// is mounted. Tag `2`.
Taken,
/// The proxy did not make the mount: its error, verbatim. Tag `3`.
///
/// Nothing is mounted. See
/// [`shared::error::Error`](crate::shared::error::Error) for why it
/// says so little.
Error(Error),
}
/// Tag for [`Frame::Mounted`].
const MOUNTED: u8 = 0;
/// Tag for [`Frame::Overlaps`].
const OVERLAPS: u8 = 1;
/// Tag for [`Frame::Taken`].
const TAKEN: u8 = 2;
/// Tag for [`Frame::Error`].
const ERROR: u8 = 3;
/// A tag, and — for the error alone — that variant's own JSON.
impl Encode for Frame {
/// The ordinary JSON failure. The bare answers 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::Mounted => {
out.extend_from_slice(&[MOUNTED]);
Ok(())
}
Frame::Overlaps => {
out.extend_from_slice(&[OVERLAPS]);
Ok(())
}
Frame::Taken => {
out.extend_from_slice(&[TAKEN]);
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 JSON.
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 {
MOUNTED => Ok(Frame::Mounted),
OVERLAPS => Ok(Frame::Overlaps),
TAKEN => Ok(Frame::Taken),
ERROR => Error::decode(rest).map(Frame::Error).map_err(FrameError::Error),
tag => Err(FrameError::UnknownTag(tag)),
}
}
}
/// A FUSE mount made while a container runs 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 four.
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("fuse mount response frame is empty"),
FrameError::UnknownTag(tag) => write!(f, "unknown fuse mount response frame tag {tag}"),
FrameError::Error(error) => write!(f, "fuse mount 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,
}
}
}