Response
The sequence of channel responses that answers the channel, what ends it, and what a finish with nothing before it means.
[0][bytes …] a piece of the file
[1][error JSON …] the content was not supplied
- The sequence. Zero or more channel responses whose first byte
is
0, each a piece of the file in order, followed by the channel response finish; or the channel responses sent so far, exactly one channel response whose first byte is1, and the channel response finish. - The error. A channel that ends in the error is a write abandoned: the server discards the temporary and answers the scope with the error.
- A finish with nothing. A channel response finish that no channel response precedes is a file of zero bytes.
The channel response is defined by diverge-sdk-rs/src/container_proxy/outside/endpoints/filesystem/write/client/channel_response/content/frame.rs:
//! What a client's channel response frame carries on a content
//! channel.
use std::fmt;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::containers::write_bytes;
use crate::shared::error::Error;
/// A piece of the file being written, or the news that there will not
/// be one.
///
/// A payload leads with one byte saying which — `0` for
/// [`Body`](Self::Body), `1` for [`Error`](Self::Error) — and the rest
/// is that variant's own bytes.
///
/// # How it ends
///
/// | the channel ends with | means |
/// |-----------------------|-------|
/// | bodies, then a finish | that was the whole content |
/// | an [`Error`](Self::Error), then a finish | the full content was not streamed |
///
/// Only a finish ends it. A write whose content ended in an error is
/// abandoned: the proxy discards what it wrote, and answers the
/// scope with an error of its own.
///
/// # The failure is this scope's, the bytes are not
///
/// [`Body`](Self::Body) carries
/// [`write_bytes::response::Frame`](crate::shared::containers::write_bytes::response::Frame),
/// which is what a piece of a file is anywhere. The
/// [`Error`](Self::Error) beside it is the exchange's own.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame<'a> {
/// A piece of the file. Tag `0`.
Body(write_bytes::response::Frame<'a>),
/// A failure. Tag `1`.
///
/// The server cannot supply the content it was asked for — the
/// caller's source went away, the read it was piping stopped,
/// whatever it knows. See
/// [`shared::error::Error`](crate::shared::error::Error) for why
/// it says so little.
Error(Error),
}
/// Tag for [`Frame::Body`].
const BODY: u8 = 0;
/// Tag for [`Frame::Error`].
const ERROR: u8 = 1;
impl Encode for Frame<'_> {
/// The ordinary JSON failure, from the half that has one. Copying
/// a slice into a buffer 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::Body(body) => {
out.extend_from_slice(&[BODY]);
// Its error is `Infallible`, and an empty match on one
// is how you say so: there is no value to handle.
body.encode(out).map_err(|error| match error {})
}
Frame::Error(error) => {
out.extend_from_slice(&[ERROR]);
error.encode(out)
}
}
}
}
impl<'a> Decode<'a> for Frame<'a> {
/// Three ways to fail, and only one of them is a parse.
type Error = FrameError;
// Spelled out for the same reason as `encode` above.
fn decode(bytes: &'a [u8]) -> Result<Self, FrameError> {
let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
match *tag {
BODY => write_bytes::response::Frame::decode(rest)
.map(Frame::Body)
.map_err(|error| match error {}),
ERROR => {
Error::decode(rest).map(Frame::Error).map_err(FrameError::Error)
}
tag => Err(FrameError::UnknownTag(tag)),
}
}
}
/// A write content frame that could not be read.
#[derive(Debug)]
pub enum FrameError {
/// No bytes at all, so not even a tag.
///
/// Distinct from a zero-length body, which is a tag followed by
/// nothing and is ordinary on a stream.
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("write content frame is empty"),
FrameError::UnknownTag(tag) => {
write!(f, "unknown write content frame tag {tag}")
}
FrameError::Error(error) => {
write!(f, "write content 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,
}
}
}
and by diverge-sdk-rs/src/shared/containers/write_bytes/response/frame.rs:
//! A write's content, arriving.
use std::convert::Infallible;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
/// A piece of the file being written.
///
/// Bytes and nothing else — no tag, because there is nothing here to
/// discriminate. This is the CONTENT, and content is the same content
/// wherever a write happens.
///
/// # Failing is not this type's business
///
/// Whether a channel carrying this can also carry a failure is the
/// endpoint's to decide, and the endpoints that allow one wrap this in
/// an enum of their own — every
/// [`containers`](crate::provider::endpoints::containers) scope does.
///
/// Putting the failure here would mean one vocabulary of errors for
/// every endpoint that ever streams a write, decided by whichever
/// needed one first. What can go wrong is endpoint logic; what a piece
/// of a file looks like is not.
///
/// # How it ends
///
/// With a finish, and only with a finish. There is no terminator in
/// the payload because the frame layer already has one, and a second
/// would be two signals for one fact.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Frame<'a>(
/// The bytes, borrowed from the frame they arrived in.
pub &'a [u8],
);
impl Encode for Frame<'_> {
/// [`Infallible`]: copying a slice into a buffer has no failure
/// mode.
type Error = Infallible;
fn encode(&self, out: &mut Writer<'_>) -> Result<(), Self::Error> {
out.extend_from_slice(self.0);
Ok(())
}
}
impl<'a> Decode<'a> for Frame<'a> {
/// [`Infallible`]: there is nothing to get wrong about a slice
/// that is already the answer.
type Error = Infallible;
fn decode(bytes: &'a [u8]) -> Result<Self, Self::Error> {
Ok(Frame(bytes))
}
}