Response
The server sends Ok once the mount is serving and nothing more on the scope for its own life, or an error, UTF-8, and the finish.
[0] ok: the mount is serving
[1][message …] not made: why not, UTF-8
- The sequence. Exactly one response whose first byte is
0, and no response finish for the life of the server; or exactly one response whose first byte is1, followed by the response finish. - The message. The bytes after the byte
1are UTF-8, not JSON: the reason the mount was not made. - 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/fuse/mount/server/response/frame.rs:
//! What a server's response frame carries for a FUSE mount.
/// `Ok` once the mount is complete — the mount point made, the
/// session started, the path serving — and then the scope stays open
/// for the proxy's life; or `Error` with why not, then the finish:
/// the path empty or the root, a path the proxy already mounted, a
/// mount point it could not make, no FUSE on the host, a session that
/// would not start. See [`ack::Frame`](crate::shared::containers::fuse::ack::Frame).
///
/// An alias rather than a re-export because this module is real: the
/// path says this scope'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<'a> = crate::shared::containers::fuse::ack::Frame<'a>;
and by diverge-sdk-rs/src/shared/containers/fuse/ack/frame.rs:
//! Ok, or why not.
use std::convert::Infallible;
use super::super::ResponseError;
use crate::wire::encode::{Encode, Writer};
/// The one message that answers a mutation.
///
/// ```text
/// [kind: u8][message…]
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Frame<'a> {
/// Kind `0`. It happened: the caller holds the result.
Ok,
/// Kind `1`. It did not, and this says why, for a reader rather
/// than a program: what a caller can refuse — a mount it keeps
/// unchangeable, a directory it will not empty, a path it will not
/// serve — is its policy and not this specification's.
Error(&'a str),
/// Kind `2`. It did not, because the volume behind the mount is
/// read only: its mode is
/// [`ReadOnly`](crate::provider::endpoints::volumes::Mode::ReadOnly), and
/// no change is made to it. Nothing after the kind. The program
/// sees a read-only filesystem, `EROFS`, and every immutable ask
/// on the same mount goes through.
ReadOnly,
}
impl Encode for Frame<'_> {
/// [`Infallible`]: a kind byte and bytes copied.
type Error = Infallible;
fn encode(&self, out: &mut Writer<'_>) -> Result<(), Infallible> {
match self {
Frame::Ok => out.extend_from_slice(&[0]),
Frame::Error(message) => {
out.extend_from_slice(&[1]);
out.extend_from_slice(message.as_bytes());
}
Frame::ReadOnly => out.extend_from_slice(&[2]),
}
Ok(())
}
}
impl<'a> Frame<'a> {
/// Decode the one message. The message borrows from `bytes`.
pub fn decode(bytes: &'a [u8]) -> Result<Self, ResponseError> {
let (kind, rest) = bytes.split_first().ok_or(ResponseError::Empty)?;
match *kind {
0 => Ok(Frame::Ok),
1 => std::str::from_utf8(rest)
.map(Frame::Error)
.map_err(|_| ResponseError::MessageUtf8),
2 => Ok(Frame::ReadOnly),
other => Err(ResponseError::UnknownKind(other)),
}
}
}