diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a51a0e7f..ef1ef3ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,7 @@ * lmdb: remove `thiserror` and `tracing` deps ([Yuki Kishimoto]) * indexeddb: remove `thiserror` and `tracing` deps ([Yuki Kishimoto]) * zapper: remove `thiserror` dep ([Yuki Kishimoto]) -* pool: remove `tokio-stream` dep ([Yuki Kishimoto]) +* pool: remove `thiserror` and `tokio-stream` deps ([Yuki Kishimoto]) * nwc: remove `thiserror` dep and unnecessary `Error::Zapper` variant ([Yuki Kishimoto]) * ffi: drop support for `i686-linux-android` target ([Yuki Kishimoto]) * ffi: remove `MockRelay` ([Yuki Kishimoto]) diff --git a/Cargo.lock b/Cargo.lock index bf4f39392..b9b027425 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3272,7 +3272,6 @@ dependencies = [ "nostr", "nostr-database", "nostr-relay-builder", - "thiserror", "tokio", "tracing", "tracing-subscriber", diff --git a/crates/nostr-relay-pool/Cargo.toml b/crates/nostr-relay-pool/Cargo.toml index 835382cae..1ea4f3013 100644 --- a/crates/nostr-relay-pool/Cargo.toml +++ b/crates/nostr-relay-pool/Cargo.toml @@ -24,7 +24,6 @@ negentropy = { workspace = true, features = ["std"] } negentropy-deprecated = { workspace = true, features = ["std"] } nostr = { workspace = true, features = ["std"] } nostr-database.workspace = true -thiserror.workspace = true tokio = { workspace = true, features = ["macros", "sync"] } tracing.workspace = true diff --git a/crates/nostr-relay-pool/src/pool/error.rs b/crates/nostr-relay-pool/src/pool/error.rs index ef4a42699..ff733e573 100644 --- a/crates/nostr-relay-pool/src/pool/error.rs +++ b/crates/nostr-relay-pool/src/pool/error.rs @@ -2,63 +2,87 @@ // Copyright (c) 2023-2024 Rust Nostr Developers // Distributed under the MIT software license -use core::convert::Infallible; +use std::convert::Infallible; +use std::fmt; use nostr::types::url; use nostr_database::DatabaseError; -use thiserror::Error; use crate::relay; /// Relay Pool error -#[derive(Debug, Error)] +#[derive(Debug)] pub enum Error { /// Url parse error - #[error("impossible to parse relay URL: {0}")] - RelayUrl(#[from] url::Error), + RelayUrl(url::Error), /// Relay error - #[error(transparent)] - Relay(#[from] relay::Error), + Relay(relay::Error), /// Database error - #[error(transparent)] - Database(#[from] DatabaseError), - /// No relays - #[error("too many relays (limit: {limit})")] + Database(DatabaseError), + /// Infallible + Infallible(Infallible), + /// Notification Handler error + Handler(String), + /// Too many relays TooManyRelays { /// Max numer allowed limit: usize, }, /// No relays - #[error("no relays")] NoRelays, /// No relays specified - #[error("no relays specified")] NoRelaysSpecified, - /// Msg not sent - #[error("message not sent")] - MsgNotSent, - /// Msgs not sent - #[error("messages not sent")] - MsgsNotSent, - /// Event/s not published - #[error("event/s not published")] - EventNotPublished, - /// Not subscribed - #[error("not subscribed")] - NotSubscribed, + /// Failed + Failed, /// Negentropy reconciliation failed - #[error("negentropy reconciliation failed")] NegentropyReconciliationFailed, /// Relay not found - #[error("relay not found")] RelayNotFound, /// Relay Pool is shutdown - #[error("Relay Pool is shutdown")] Shutdown, - /// Notification Handler error - #[error("notification handler error: {0}")] - Handler(String), - /// Infallible - #[error(transparent)] - Infallible(#[from] Infallible), +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::RelayUrl(e) => write!(f, "{e}"), + Self::Relay(e) => write!(f, "{e}"), + Self::Database(e) => write!(f, "{e}"), + Self::Infallible(e) => write!(f, "{e}"), + Self::Handler(e) => write!(f, "{e}"), + Self::TooManyRelays { limit } => write!(f, "too many relays (limit: {limit})"), + Self::NoRelays => write!(f, "no relays"), + Self::NoRelaysSpecified => write!(f, "no relays specified"), + Self::Failed => write!(f, "completed without success"), // TODO: better error? + Self::NegentropyReconciliationFailed => write!(f, "negentropy reconciliation failed"), + Self::RelayNotFound => write!(f, "relay not found"), + Self::Shutdown => write!(f, "relay pool is shutdown"), + } + } +} + +impl From for Error { + fn from(e: url::Error) -> Self { + Self::RelayUrl(e) + } +} + +impl From for Error { + fn from(e: relay::Error) -> Self { + Self::Relay(e) + } +} + +impl From for Error { + fn from(e: DatabaseError) -> Self { + Self::Database(e) + } +} + +impl From for Error { + fn from(e: Infallible) -> Self { + Self::Infallible(e) + } } diff --git a/crates/nostr-relay-pool/src/pool/inner.rs b/crates/nostr-relay-pool/src/pool/inner.rs index f07a24f12..c481ae7cf 100644 --- a/crates/nostr-relay-pool/src/pool/inner.rs +++ b/crates/nostr-relay-pool/src/pool/inner.rs @@ -393,7 +393,7 @@ impl InnerRelayPool { } if output.success.is_empty() { - return Err(Error::MsgNotSent); + return Err(Error::Failed); } Ok(output) @@ -469,7 +469,7 @@ impl InnerRelayPool { } if output.success.is_empty() { - return Err(Error::EventNotPublished); + return Err(Error::Failed); } Ok(output) @@ -611,7 +611,7 @@ impl InnerRelayPool { } if output.success.is_empty() { - return Err(Error::NotSubscribed); + return Err(Error::Failed); } Ok(output) diff --git a/crates/nostr-relay-pool/src/relay/error.rs b/crates/nostr-relay-pool/src/relay/error.rs index e781767ff..39b3c3cd4 100644 --- a/crates/nostr-relay-pool/src/relay/error.rs +++ b/crates/nostr-relay-pool/src/relay/error.rs @@ -2,108 +2,74 @@ // Copyright (c) 2023-2024 Rust Nostr Developers // Distributed under the MIT software license -use std::collections::HashMap; +use std::fmt; use std::time::Duration; use nostr::event::builder; use nostr::message::relay::NegentropyErrorCode; use nostr::message::MessageHandleError; -use nostr::{event, EventId, Kind}; +use nostr::{event, Kind}; use nostr_database::DatabaseError; -use thiserror::Error; use tokio::sync::{broadcast, SetError}; use crate::shared::SharedStateError; use crate::RelayPoolNotification; /// Relay error -#[derive(Debug, Error)] +#[derive(Debug)] pub enum Error { /// Shared state error - #[error(transparent)] - SharedState(#[from] SharedStateError), + SharedState(SharedStateError), /// MessageHandle error - #[error(transparent)] - MessageHandle(#[from] MessageHandleError), + MessageHandle(MessageHandleError), /// Event error - #[error(transparent)] - Event(#[from] event::Error), + Event(event::Error), /// Event Builder error - #[error(transparent)] - EventBuilder(#[from] builder::Error), + EventBuilder(builder::Error), /// Partial Event error - #[error(transparent)] - PartialEvent(#[from] event::partial::Error), + PartialEvent(event::partial::Error), /// Negentropy error - #[error(transparent)] - Negentropy(#[from] negentropy::Error), + Negentropy(negentropy::Error), /// Negentropy error - #[error(transparent)] - NegentropyDeprecated(#[from] negentropy_deprecated::Error), + NegentropyDeprecated(negentropy_deprecated::Error), /// Database error - #[error(transparent)] - Database(#[from] DatabaseError), + Database(DatabaseError), /// OnceCell error - #[error(transparent)] - OnceCell(#[from] SetError>), + SetPoolNotificationSender(SetError>), /// WebSocket timeout - #[error("WebSocket timeout")] WebSocketTimeout, /// Generic timeout - #[error("timeout")] Timeout, /// Not replied to ping - #[error("not replied to ping")] NotRepliedToPing, /// Message response timeout - #[error("Can't send message to the '{channel}' channel")] CantSendChannelMessage { /// Name of channel channel: String, }, + /// Relay not ready + NotReady, /// Relay not connected - #[error("relay is initialized but not ready")] - Initialized, - /// Relay not connected - #[error("relay not connected")] NotConnected, /// Received shutdown - #[error("received shutdown")] Shutdown, /// Relay message - #[error("{0}")] RelayMessage(String), - /// Only some events - #[error("partial publish: published={}, missing={}", published.len(), not_published.len())] - PartialPublish { - /// Published events - published: Vec, - /// Not published events - not_published: HashMap, - }, /// Batch messages empty - #[error("can't batch empty list of messages")] BatchMessagesEmpty, /// Read actions disabled - #[error("read actions are disabled for this relay")] ReadDisabled, /// Write actions disabled - #[error("write actions are disabled for this relay")] WriteDisabled, /// Filters empty - #[error("filters empty")] FiltersEmpty, /// Reconciliation error - #[error("negentropy reconciliation error: {0}")] NegentropyReconciliation(NegentropyErrorCode), /// Negentropy not supported - #[error("negentropy (maybe) not supported")] NegentropyMaybeNotSupported, /// Unknown negentropy error - #[error("unknown negentropy error")] UnknownNegentropyError, /// Relay message too large - #[error("Received message too large: size={size}, max_size={max_size}")] RelayMessageTooLarge { /// Message size size: usize, @@ -111,7 +77,6 @@ pub enum Error { max_size: usize, }, /// Event too large - #[error("Received event too large: size={size}, max_size={max_size}")] EventTooLarge { /// Event size size: usize, @@ -119,7 +84,6 @@ pub enum Error { max_size: usize, }, /// Too many tags - #[error("Received event with too many tags: tags={size}, max_tags={max_size}")] TooManyTags { /// Tags num size: usize, @@ -127,16 +91,13 @@ pub enum Error { max_size: usize, }, /// Event expired - #[error("event expired")] EventExpired, /// POW difficulty too low - #[error("POW difficulty too low (min. {min})")] PowDifficultyTooLow { /// Min. difficulty min: u8, }, /// Unexpected kind - #[error("Unexpected kind: expected={expected}, found={found}")] UnexpectedKind { /// Expected kind expected: Kind, @@ -144,13 +105,10 @@ pub enum Error { found: Kind, }, /// Notification Handler error - #[error("notification handler error: {0}")] Handler(String), /// WebSocket error - #[error("{0}")] WebSocket(Box), /// Max latency exceeded - #[error("Maximum latency exceeded: max={}ms, current={}ms", max.as_millis(), current.as_millis())] MaximumLatencyExceeded { /// Max max: Duration, @@ -158,13 +116,73 @@ pub enum Error { current: Duration, }, /// Auth failed - #[error("authentication failed")] AuthenticationFailed, /// Premature exit - #[error("premature exit")] PrematureExit, } +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::SharedState(e) => write!(f, "{e}"), + Self::MessageHandle(e) => write!(f, "{e}"), + Self::Event(e) => write!(f, "{e}"), + Self::EventBuilder(e) => write!(f, "{e}"), + Self::PartialEvent(e) => write!(f, "{e}"), + Self::Negentropy(e) => write!(f, "{e}"), + Self::NegentropyDeprecated(e) => write!(f, "{e}"), + Self::Database(e) => write!(f, "{e}"), + Self::SetPoolNotificationSender(e) => write!(f, "{e}"), + Self::WebSocketTimeout => write!(f, "WebSocket timeout"), + Self::Timeout => write!(f, "timeout"), + Self::NotRepliedToPing => write!(f, "not replied to ping"), + Self::CantSendChannelMessage { channel } => { + write!(f, "can't send message to the '{channel}' channel") + } + Self::NotReady => write!(f, "relay is initialized but not ready"), + Self::NotConnected => write!(f, "relay not connected"), + Self::Shutdown => write!(f, "received shutdown"), + Self::RelayMessage(message) => write!(f, "{message}"), + Self::BatchMessagesEmpty => write!(f, "can't batch empty list of messages"), + Self::ReadDisabled => write!(f, "read actions are disabled"), + Self::WriteDisabled => write!(f, "write actions are disabled"), + Self::FiltersEmpty => write!(f, "filters empty"), + Self::NegentropyReconciliation(e) => write!(f, "{e}"), + Self::NegentropyMaybeNotSupported => write!(f, "negentropy (maybe) not supported"), + Self::UnknownNegentropyError => write!(f, "unknown negentropy error"), + Self::RelayMessageTooLarge { size, max_size } => write!( + f, + "Received message too large: size={size}, max_size={max_size}" + ), + Self::EventTooLarge { size, max_size } => write!( + f, + "Received event too large: size={size}, max_size={max_size}" + ), + Self::TooManyTags { size, max_size } => write!( + f, + "Received event with too many tags: tags={size}, max_tags={max_size}" + ), + Self::EventExpired => write!(f, "event expired"), + Self::PowDifficultyTooLow { min } => write!(f, "POW difficulty too low (min. {min})"), + Self::UnexpectedKind { expected, found } => { + write!(f, "Unexpected kind: expected={expected}, found={found}") + } + Self::Handler(e) => write!(f, "{e}"), + Self::WebSocket(e) => write!(f, "{e}"), + Self::MaximumLatencyExceeded { max, current } => write!( + f, + "Maximum latency exceeded: max={}ms, current={}ms", + max.as_millis(), + current.as_millis() + ), + Self::AuthenticationFailed => write!(f, "authentication failed"), + Self::PrematureExit => write!(f, "premature exit"), + } + } +} + impl Error { #[inline] pub(super) fn websocket(error: E) -> Self @@ -174,3 +192,57 @@ impl Error { Self::WebSocket(Box::new(error)) } } + +impl From for Error { + fn from(e: SharedStateError) -> Self { + Self::SharedState(e) + } +} + +impl From for Error { + fn from(e: MessageHandleError) -> Self { + Self::MessageHandle(e) + } +} + +impl From for Error { + fn from(e: event::Error) -> Self { + Self::Event(e) + } +} + +impl From for Error { + fn from(e: builder::Error) -> Self { + Self::EventBuilder(e) + } +} + +impl From for Error { + fn from(e: event::partial::Error) -> Self { + Self::PartialEvent(e) + } +} + +impl From for Error { + fn from(e: negentropy::Error) -> Self { + Self::Negentropy(e) + } +} + +impl From for Error { + fn from(e: negentropy_deprecated::Error) -> Self { + Self::NegentropyDeprecated(e) + } +} + +impl From for Error { + fn from(e: DatabaseError) -> Self { + Self::Database(e) + } +} + +impl From>> for Error { + fn from(e: SetError>) -> Self { + Self::SetPoolNotificationSender(e) + } +} diff --git a/crates/nostr-relay-pool/src/relay/inner.rs b/crates/nostr-relay-pool/src/relay/inner.rs index a3de6335c..02d031434 100644 --- a/crates/nostr-relay-pool/src/relay/inner.rs +++ b/crates/nostr-relay-pool/src/relay/inner.rs @@ -234,9 +234,9 @@ impl InnerRelay { fn health_check(&self) -> Result<(), Error> { let status: RelayStatus = self.status(); - // Relay initialized (never called connect method) + // Relay not ready (never called connect method) if status.is_initialized() { - return Err(Error::Initialized); + return Err(Error::NotReady); } if !status.is_connected() diff --git a/crates/nostr-relay-pool/src/shared.rs b/crates/nostr-relay-pool/src/shared.rs index 427f56fc1..82132d303 100644 --- a/crates/nostr-relay-pool/src/shared.rs +++ b/crates/nostr-relay-pool/src/shared.rs @@ -2,23 +2,32 @@ // Copyright (c) 2023-2024 Rust Nostr Developers // Distributed under the MIT software license +use std::fmt; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use nostr::prelude::IntoNostrSigner; use nostr::NostrSigner; use nostr_database::{IntoNostrDatabase, MemoryDatabase, NostrDatabase}; -use thiserror::Error; use tokio::sync::RwLock; use crate::{RelayFiltering, RelayFilteringMode}; -#[derive(Debug, Error)] +#[derive(Debug)] pub enum SharedStateError { - #[error("signer not configured")] SignerNotConfigured, } +impl std::error::Error for SharedStateError {} + +impl fmt::Display for SharedStateError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::SignerNotConfigured => write!(f, "signer not configured"), + } + } +} + // TODO: add SharedStateBuilder? #[derive(Debug, Clone)]