#![allow(unused_assignments)]
use crate::manager::ManagerAction;
use crate::packet::{DynAck, Signal};
use bytes::Bytes;
use bytestring::ByteString;
use eioc::engine::EngineAction;
use miette::Diagnostic;
use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
use tokio::task::JoinError;
use tokio::time::error::Elapsed;
#[derive(Debug, Error, Diagnostic)]
#[error("payload error for `{type_name}`: {source}")]
#[diagnostic(code(sioc::payload))]
pub struct PayloadError {
type_name: &'static str,
#[source]
source: serde_path_to_error::Error<serde_json::Error>,
}
impl PayloadError {
pub fn new<T>(source: serde_path_to_error::Error<serde_json::Error>) -> Self {
Self {
type_name: std::any::type_name::<T>(),
source,
}
}
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Error, Diagnostic)]
#[error(transparent)]
#[diagnostic(transparent)]
pub enum Error {
Builder(#[from] ClientBuilderError),
Client(#[from] ClientError),
Socket(#[from] SocketError),
Event(#[from] EventError),
Ack(#[from] AckError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum ClientBuilderError {
#[error("invalid URL")]
#[diagnostic(code(sioc::builder::url))]
Url(#[from] url::ParseError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum ClientError {
#[error(transparent)]
#[diagnostic(transparent)]
Manager(#[from] ManagerError),
#[error("failed to join socket manager task")]
#[diagnostic(code(sioc::client::join))]
Join(#[from] JoinError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum SocketError {
#[error("failed to send directive to socket manager")]
#[diagnostic(code(sioc::socket::send))]
Send(#[from] mpsc::error::SendError<ManagerAction>),
#[error("failed to serialize payload")]
#[diagnostic(code(sioc::socket::payload))]
Payload(#[from] PayloadError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum EventError {
#[error("failed to deserialize event payload")]
#[diagnostic(code(sioc::event::payload))]
Payload(#[from] PayloadError),
#[error("invalid ack ID for the event type")]
#[diagnostic(code(sioc::event::ack_id))]
AckId(#[from] AckIdError),
#[error("invalid attachments for the event type")]
#[diagnostic(code(sioc::event::attachments))]
Attachments(#[from] AttachmentsError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum AckError {
#[error("failed to receive ack")]
#[diagnostic(
code(sioc::ack::recv),
help("the ack sender was dropped before responding; the connection may have been lost")
)]
Recv(#[from] oneshot::error::RecvError),
#[error("failed to parse ack payload")]
#[diagnostic(code(sioc::ack::payload))]
Payload(#[from] PayloadError),
#[error("invalid attachments for the ack type")]
#[diagnostic(code(sioc::ack::attachments))]
Attachments(#[from] AttachmentsError),
#[error("ack timed out")]
#[diagnostic(code(sioc::ack::timeout))]
Timeout(#[from] Elapsed),
}
#[derive(Debug, Error, Diagnostic)]
pub enum AckIdError {
#[error("ack ID was missing")]
#[diagnostic(
code(sioc::ack_id::missing),
help(
"event type declares `HasAck` but the server sent no ack ID; verify the server's protocol"
)
)]
Missing,
#[error("ack ID was unexpected")]
#[diagnostic(
code(sioc::ack_id::unexpected),
help(
"event type declares `NoAck` but the server sent an ack ID; consider using `HasAck<A>`"
)
)]
Unexpected,
}
#[derive(Debug, Error, Diagnostic)]
pub enum AttachmentsError {
#[error("attachments were missing")]
#[diagnostic(
code(sioc::attachments::missing),
help(
"type declares `HasBinary` but no attachments were in the packet; verify the server's protocol"
)
)]
Missing,
#[error("attachments were unexpected")]
#[diagnostic(
code(sioc::attachments::unexpected),
help(
"type declares `NoBinary` but the packet contained attachments; consider using `HasBinary`"
)
)]
Unexpected,
}
#[derive(Debug, Error, Diagnostic)]
pub enum PacketError {
#[error(transparent)]
#[diagnostic(code(sioc::parse::json))]
Json(#[from] serde_json::Error),
#[error("invalid UTF-8 in packet")]
#[diagnostic(code(sioc::parse::utf8))]
Utf8(#[from] std::str::Utf8Error),
#[error("packet is empty")]
#[diagnostic(code(sioc::parse::empty_packet))]
Empty,
#[error("unknown packet type {id}")]
#[diagnostic(code(sioc::parse::unknown_packet_type))]
InvalidId { id: char },
#[error("binary packet missing attachment count prefix")]
#[diagnostic(code(sioc::parse::missing_attachment_count))]
MissingAttachmentCount,
#[error("text event packet has unexpected attachment count ({count})")]
#[diagnostic(code(sioc::parse::unexpected_attachments))]
UnexpectedAttachments { count: usize },
#[error("attachment count is not a valid integer")]
#[diagnostic(code(sioc::parse::invalid_attachment_count))]
InvalidAttachmentCount(#[source] std::num::ParseIntError),
#[error("namespace missing trailing `,` delimiter")]
#[diagnostic(code(sioc::parse::missing_namespace_delimiter))]
MissingNamespaceDelimiter,
#[error("ack packet missing numeric ID")]
#[diagnostic(code(sioc::parse::missing_ack_id))]
MissingAckId,
#[error("packet ID is not a valid integer")]
#[diagnostic(code(sioc::parse::invalid_ack_id))]
InvalidAckId(#[source] std::num::ParseIntError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum ManagerError {
#[error(transparent)]
#[diagnostic(transparent)]
Engine(#[from] eioc::error::Error),
#[error(transparent)]
#[diagnostic(transparent)]
Packet(#[from] PacketError),
#[error("engine action channel closed")]
#[diagnostic(
code(sioc::manager::send_engine),
help("the receiver was dropped; the socket is probably shut down")
)]
SendEngine(#[from] mpsc::error::SendError<EngineAction>),
#[error("manager send failed for namespace `{ns}`")]
#[diagnostic(
code(sioc::manager::send_socket),
help("the receiver was dropped; the socket is probably shut down")
)]
SendSocket {
ns: ByteString,
#[source]
source: mpsc::error::SendError<Signal>,
},
#[error("ack channel closed for namespace `{ns}`")]
#[diagnostic(
code(sioc::manager::send_ack),
help("the ack receiver was dropped; the namespace may have disconnected")
)]
SendAck { ns: ByteString, ack: DynAck },
#[error("unexpected text frame: {0:?}")]
#[diagnostic(
code(sioc::manager::unexpected_text),
help(
"the server sent a text frame while binary reassembly was in progress; likely a server protocol bug"
)
)]
UnexpectedText(ByteString),
#[error("unexpected binary frame: {0:?}")]
#[diagnostic(
code(sioc::manager::unexpected_binary),
help(
"the server sent a binary frame while no reassembly was pending; likely a server protocol bug"
)
)]
UnexpectedBinary(Bytes),
#[error("unknown namespace `{ns}`")]
#[diagnostic(
code(sioc::manager::unknown_namespace),
help("connect the namespace before sending or receiving on it")
)]
UnknownNamespace { ns: ByteString },
#[error("ack for unknown ID {id} in namespace `{ns}`")]
#[diagnostic(
code(sioc::manager::unknown_ack_id),
help(
"the server sent an ack for an unregistered ID; the server may be replying to an already-acknowledged event"
)
)]
UnknownAckId { ns: ByteString, id: u64 },
#[error("namespace conflict: `{ns}`")]
#[diagnostic(
code(sioc::manager::namespace_conflict),
help("the namespace is already open; drop the existing handle before reconnecting")
)]
NamespaceConflict { ns: ByteString },
}