use std::io;
use bytes::BytesMut;
use prost::DecodeError;
use tokio::sync::oneshot;
use crate::{
peer_manager::NodeId,
proto,
protocol::rpc::{handshake::RpcHandshakeError, server::early_close::EarlyCloseError},
};
#[derive(Debug, thiserror::Error)]
pub enum RpcServerError {
#[error("Failed to decode message: {0}")]
DecodeError(#[from] DecodeError),
#[error("IO Error: {0}")]
Io(#[from] io::Error),
#[error("Maximum number of RPC sessions reached: {0}")]
MaximumSessionsReached(String),
#[error("Maximum number of client RPC sessions reached for node {node_id}")]
MaxSessionsPerClientReached { node_id: NodeId, max_sessions: usize },
#[error("Internal service request canceled")]
RequestCanceled,
#[error("Stream was closed by remote")]
StreamClosedByRemote,
#[error("Handshake error: {0}")]
HandshakeError(#[from] RpcHandshakeError),
#[error("Service not found for protocol `{0}`")]
ProtocolServiceNotFound(String),
#[error("Unexpected incoming message")]
UnexpectedIncomingMessage(proto::rpc::RpcRequest),
#[error("Unexpected incoming MALFORMED message")]
UnexpectedIncomingMessageMalformed,
#[error("Client interrupted stream")]
ClientInterruptedStream,
#[error("Service call exceeded deadline")]
ServiceCallExceededDeadline,
#[error("Stream read exceeded deadline")]
ReadStreamExceededDeadline,
#[error("Early close: {0}")]
EarlyClose(#[from] EarlyCloseError<BytesMut>),
#[error("Protocol error: {0}")]
ProtocolError(String),
}
impl RpcServerError {
pub fn early_close_io(&self) -> Option<&io::Error> {
match self {
Self::EarlyClose(e) => e.io(),
_ => None,
}
}
}
impl From<oneshot::error::RecvError> for RpcServerError {
fn from(_: oneshot::error::RecvError) -> Self {
RpcServerError::RequestCanceled
}
}
impl RpcServerError {
pub fn to_debug_string(&self) -> String {
#[allow(clippy::enum_glob_use)]
use RpcServerError::*;
match self {
DecodeError(_) => "DecodeError".to_string(),
Io(err) => {
format!("Io({:?})", err.kind())
},
HandshakeError(_) => "HandshakeError".to_string(),
ProtocolServiceNotFound(_) => "ProtocolServiceNotFound".to_string(),
UnexpectedIncomingMessage(_) => "UnexpectedIncomingMessage".to_string(),
err => {
format!("{err:?}")
},
}
}
}