Response
The server sends exactly one response: the byte 0 alone, Serving, after which the scope stays open until the client stops it; or the byte 1 followed by an error as one JSON value, and the finish.
The server sends exactly one response on the scope, and sends it before it serves any channel.
[0] serving: the directory is served, and the asks are answered
[1][error JSON …] not served
- The sequence. Exactly one response, first. After a response
whose payload is exactly the one byte
0, the scope stays open: the server sends no other response on the scope, answers every channel the client opens as Client Channels states, and sends the response finish after the last answer when the client stops. After a response whose first byte is1, the response finish follows the response, and no frame follows the finish. - The error. A payload whose first byte is
1carries 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 page. This revision prescribes nothing about its content. - A finish with nothing. A response finish that no response precedes states that the server could not read the request.
The response is defined by diverge-sdk-rs/src/container_proxy/outside/endpoints/filesystem/fuse_serve/server/response/frame.rs:
//! What a server's response frame carries for a FUSE serve.
use std::fmt;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::error::Error;
/// The subtree is served, or the news that it will not be.
///
/// A payload leads with one byte saying which — `0` for
/// [`Serving`](Self::Serving), `1` for [`Error`](Self::Error) — and
/// the rest is that variant's own bytes, of which `Serving` has none.
///
/// # How the scope runs
///
/// | the scope | means |
/// |-----------|-------|
/// | a serving, then quiet, and stays open | the subtree is served, and every ask the server opens is answered on its channel |
/// | a serving, then a finish | the server stopped |
/// | an error, then a finish | it was not served: the path is not a directory of the container, or is one the proxy leaves out |
///
/// Exactly one response, first. Nothing else comes on channel `0`;
/// the answers to asks come on the asks' channels.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
/// The subtree is served, and asks may be opened. Tag `0`.
Serving,
/// A failure. Tag `1`.
///
/// See [`shared::error::Error`](crate::shared::error::Error) for
/// why it says so little.
Error(Error),
}
/// Tag for [`Frame::Serving`].
const SERVING: u8 = 0;
/// Tag for [`Frame::Error`].
const ERROR: u8 = 1;
impl Encode for Frame {
/// The ordinary JSON failure, from the half that has one.
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::Serving => {
out.extend_from_slice(&[SERVING]);
Ok(())
}
Frame::Error(error) => {
out.extend_from_slice(&[ERROR]);
error.encode(out)
}
}
}
}
impl Decode<'_> for Frame {
/// Three ways to fail, and 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 {
SERVING => Ok(Frame::Serving),
ERROR => Error::decode(rest).map(Frame::Error).map_err(FrameError::Error),
tag => Err(FrameError::UnknownTag(tag)),
}
}
}
/// A FUSE serve 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 neither of this frame'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("FUSE serve response frame is empty"),
FrameError::UnknownTag(tag) => write!(f, "unknown FUSE serve response frame tag {tag}"),
FrameError::Error(error) => write!(f, "FUSE serve 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,
}
}
}