use crate::node::OpManager;
use crate::operations::OpError;
use freenet_stdlib::client_api::RequestError;
#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {
#[error("Node not connected to network")]
Disconnected,
#[error("subscriber registration rejected: {0}")]
Registration(Box<RequestError>),
#[error("Peer has not joined the network yet (no ring location established)")]
PeerNotJoined,
#[error("No ring connections found")]
EmptyRing,
#[error("Node error: {0}")]
Node(String),
#[error(transparent)]
Contract(#[from] crate::contract::ContractError),
#[error(transparent)]
Op(#[from] OpError),
#[error(transparent)]
Executor(#[from] crate::contract::ExecutorError),
#[error(transparent)]
Panic(#[from] tokio::task::JoinError),
}
impl From<crate::ring::RingError> for Error {
fn from(err: crate::ring::RingError) -> Self {
match err {
crate::ring::RingError::PeerNotJoined => Error::PeerNotJoined,
crate::ring::RingError::EmptyRing => Error::EmptyRing,
other @ crate::ring::RingError::ConnError(_)
| other @ crate::ring::RingError::NoHostingPeers(_) => Error::Node(other.to_string()),
}
}
}
pub(crate) fn ensure_peer_ready(op_manager: &OpManager) -> Result<std::net::SocketAddr, Error> {
if !op_manager.is_gateway
&& !op_manager
.peer_ready
.load(std::sync::atomic::Ordering::SeqCst)
{
return Err(Error::PeerNotJoined);
}
Ok(op_manager.ring.connection_manager.peer_addr()?)
}
#[cfg(test)]
mod tests {
use super::*;
use freenet_stdlib::client_api::ContractError as StdContractError;
use freenet_stdlib::prelude::{CodeHash, ContractInstanceId, ContractKey};
#[test]
fn registration_error_display_carries_underlying_detail() {
let key = ContractKey::from_id_and_code(
ContractInstanceId::new([7u8; 32]),
CodeHash::new([0u8; 32]),
);
let inner = RequestError::ContractError(StdContractError::Subscribe {
key,
cause: "subscriber limit (100) reached for contract".into(),
});
let err = Error::Registration(Box::new(inner));
let rendered = err.to_string();
assert!(
rendered.contains("subscriber limit"),
"the registration error must carry the underlying cause, got: {rendered}"
);
assert_ne!(
rendered,
Error::Op(OpError::UnexpectedOpState).to_string(),
"registration failure must not degrade to the generic UnexpectedOpState message"
);
}
}