Response

The server sends at most one response, an error as JSON with no tag; when the connector is attached it sends nothing, and the finish ends the connection without an error.

The server sends at most one response on the scope, an error. When the connector is attached, the server sends no response; the response finish ends the scope. No frame bearing the scope follows the finish.

[error JSON …]     at most once, when the connection is refused
  • The sequence. An error, when the server sends one, is the only response and is followed by the response finish: the container was not found, or the runner refused the connector. When the server sends no response, the connector is attached from the moment the runner authorized it, and the finish ends the connection without an error: the connector disconnected, the run ended, or the connector’s connection ended.
  • The error. The payload is exactly one JSON value, with no tag before it, in the form defined on the volumes::list response page. The server sends {"kind":"missing"} for an id that names no running container and {"kind":"denied"} for a connector the runner did not authorize.
  • Malformed. A payload that is not one JSON value is malformed.

The response is defined by diverge-provider-sdk/src/endpoints/containers/tools/connect/server/response/frame.rs:

//! What a server's response frame carries for a tool container connection.

use crate::decode::Decode;
use crate::encode::{Encode, Writer};
use crate::shared::error::Error;

/// A connection's answer, which is a failure or nothing.
///
/// One struct, no tag, at most one frame, usually zero:
///
/// | the scope | means |
/// |-----------|-------|
/// | says nothing, and stays open | the connector is attached |
/// | one of these, then a finish | it never was — the container was not there, its runner said no |
/// | a finish, with none of these | the connection is over — the connector left, or the container did |
///
/// A connector already holds the id, so there is nothing to tell it;
/// everything it reads from the container is a channel it opens.
/// An enum of one variant would be a discriminant with nothing to
/// discriminate, and a tag byte is that discriminant written on the
/// wire, so it goes for the same reason.
#[derive(Debug, Clone, PartialEq)]
pub struct Frame(
    /// Why the connection is not open. See
    /// [`shared::error::Error`](crate::shared::error::Error) for why
    /// it says so little.
    pub Error,
);

impl Encode for Frame {
    /// The ordinary JSON failure.
    type Error = serde_json::Error;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), serde_json::Error> {
        self.0.encode(out)
    }
}

impl Decode<'_> for Frame {
    /// The ordinary JSON failure.
    type Error = serde_json::Error;

    fn decode(bytes: &[u8]) -> Result<Self, serde_json::Error> {
        Error::decode(bytes).map(Frame)
    }
}