use std::{fmt::Debug, marker::PhantomData};
use stratum_apps::{
stratum_core::{
binary_sv2, codec_sv2, framing_sv2, handlers_sv2::HandlerErrorType, noise_sv2,
parsers_sv2::ParserError,
},
utils::types::{
CanDisconnect, CanShutdown, DownstreamId, ExtensionType, MessageType, RequestId,
},
};
pub type JDSResult<T, Owner> = Result<T, JDSError<Owner>>;
#[derive(Debug)]
pub struct JDSError<Owner> {
pub kind: JDSErrorKind,
pub action: Action,
_owner: PhantomData<Owner>,
}
#[derive(Debug, Clone, Copy)]
pub enum Action {
Log,
Disconnect(DownstreamId),
Shutdown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoopControl {
Continue,
Break,
}
#[derive(Debug)]
pub struct JobDeclarator;
impl CanShutdown for JobDeclarator {}
impl CanDisconnect for JobDeclarator {}
impl<O> JDSError<O>
where
O: CanShutdown,
{
pub fn shutdown<E: Into<JDSErrorKind>>(kind: E) -> Self {
Self {
kind: kind.into(),
action: Action::Shutdown,
_owner: PhantomData,
}
}
}
#[derive(Debug)]
pub struct Downstream;
impl CanDisconnect for Downstream {}
impl CanShutdown for Downstream {}
impl<O> JDSError<O>
where
O: CanDisconnect,
{
pub fn disconnect<E: Into<JDSErrorKind>>(kind: E, downstream_id: DownstreamId) -> Self {
Self {
kind: kind.into(),
action: Action::Disconnect(downstream_id),
_owner: PhantomData,
}
}
}
#[derive(Debug)]
pub enum JDSErrorKind {
Io(std::io::Error),
ChannelSend(Box<dyn std::marker::Send + Debug>),
ChannelRecv(async_channel::RecvError),
BinarySv2(binary_sv2::Error),
Codec(codec_sv2::Error),
Noise(noise_sv2::Error),
Parser(ParserError),
BitcoinCoreIPC(String),
Framing(framing_sv2::Error),
UnexpectedMessage(ExtensionType, MessageType),
ClientNotFound(DownstreamId),
ClientSenderNotFound(DownstreamId),
PendingDeclareMiningJobNotFound(RequestId),
UnsupportedProtocol,
UnsupportedConnectionFlags,
OneshotRecv(tokio::sync::oneshot::error::RecvError),
InvalidConfig(String),
}
impl<Owner> From<JDSError<Owner>> for JDSErrorKind {
fn from(value: JDSError<Owner>) -> Self {
value.kind
}
}
impl<Owner> JDSError<Owner> {
pub fn log<E: Into<JDSErrorKind>>(kind: E) -> Self {
Self {
kind: kind.into(),
action: Action::Log,
_owner: PhantomData,
}
}
}
impl From<std::io::Error> for JDSErrorKind {
fn from(e: std::io::Error) -> Self {
JDSErrorKind::Io(e)
}
}
impl From<async_channel::RecvError> for JDSErrorKind {
fn from(e: async_channel::RecvError) -> Self {
JDSErrorKind::ChannelRecv(e)
}
}
impl From<binary_sv2::Error> for JDSErrorKind {
fn from(e: binary_sv2::Error) -> Self {
JDSErrorKind::BinarySv2(e)
}
}
impl From<codec_sv2::Error> for JDSErrorKind {
fn from(e: codec_sv2::Error) -> Self {
JDSErrorKind::Codec(e)
}
}
impl From<framing_sv2::Error> for JDSErrorKind {
fn from(e: framing_sv2::Error) -> Self {
JDSErrorKind::Framing(e)
}
}
impl From<noise_sv2::Error> for JDSErrorKind {
fn from(e: noise_sv2::Error) -> Self {
JDSErrorKind::Noise(e)
}
}
impl From<ParserError> for JDSErrorKind {
fn from(e: ParserError) -> Self {
JDSErrorKind::Parser(e)
}
}
impl From<tokio::sync::oneshot::error::RecvError> for JDSErrorKind {
fn from(e: tokio::sync::oneshot::error::RecvError) -> Self {
JDSErrorKind::OneshotRecv(e)
}
}
impl<T> From<async_channel::SendError<T>> for JDSErrorKind
where
T: std::marker::Send + Debug + 'static,
{
fn from(e: async_channel::SendError<T>) -> Self {
JDSErrorKind::ChannelSend(Box::new(e))
}
}
impl<Owner> HandlerErrorType for JDSError<Owner> {
fn parse_error(error: ParserError) -> Self {
Self {
kind: JDSErrorKind::Parser(error),
action: Action::Log,
_owner: PhantomData,
}
}
fn unexpected_message(extension_type: ExtensionType, message_type: MessageType) -> Self {
Self {
kind: JDSErrorKind::UnexpectedMessage(extension_type, message_type),
action: Action::Log,
_owner: PhantomData,
}
}
}