nostr-pubsub 0.1.13

Neutral Nostr event and source routing primitives
Documentation
use async_trait::async_trait;

use crate::{EventSource, PublishReport, Result, SourceId};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PubsubStreamId(pub String);

impl PubsubStreamId {
    #[must_use]
    pub fn new(stream_id: impl Into<String>) -> Self {
        Self(stream_id.into())
    }

    #[must_use]
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PubsubContentKey {
    pub stream_id: PubsubStreamId,
    pub origin: SourceId,
    pub seq: u64,
}

impl PubsubContentKey {
    #[must_use]
    pub fn new(stream_id: impl Into<String>, origin: impl Into<String>, seq: u64) -> Self {
        Self {
            stream_id: PubsubStreamId::new(stream_id),
            origin: SourceId::new(origin),
            seq,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PubsubInventory {
    pub key: PubsubContentKey,
    pub payload_bytes: u64,
    pub hop_limit: u8,
}

impl PubsubInventory {
    #[must_use]
    pub fn new(key: PubsubContentKey, payload_bytes: u64, hop_limit: u8) -> Self {
        Self {
            key,
            payload_bytes,
            hop_limit,
        }
    }

    #[must_use]
    pub fn want(&self) -> PubsubWant {
        PubsubWant::new(self.key.clone())
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PubsubWant {
    pub key: PubsubContentKey,
}

impl PubsubWant {
    #[must_use]
    pub fn new(key: PubsubContentKey) -> Self {
        Self { key }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PubsubFrame {
    pub key: PubsubContentKey,
    pub payload: Vec<u8>,
    pub hop_limit: u8,
}

impl PubsubFrame {
    #[must_use]
    pub fn new(key: PubsubContentKey, payload: impl Into<Vec<u8>>, hop_limit: u8) -> Self {
        Self {
            key,
            payload: payload.into(),
            hop_limit,
        }
    }

    #[must_use]
    pub fn inventory(&self) -> PubsubInventory {
        PubsubInventory::new(
            self.key.clone(),
            u64::try_from(self.payload.len()).unwrap_or(u64::MAX),
            self.hop_limit,
        )
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InvWantMessage {
    Inventory(PubsubInventory),
    Want(PubsubWant),
    Frame(PubsubFrame),
}

impl InvWantMessage {
    #[must_use]
    pub fn key(&self) -> &PubsubContentKey {
        match self {
            Self::Inventory(inventory) => &inventory.key,
            Self::Want(want) => &want.key,
            Self::Frame(frame) => &frame.key,
        }
    }

    #[must_use]
    pub fn stream_id(&self) -> &PubsubStreamId {
        match self {
            Self::Inventory(inventory) => &inventory.key.stream_id,
            Self::Want(want) => &want.key.stream_id,
            Self::Frame(frame) => &frame.key.stream_id,
        }
    }
}

#[async_trait]
pub trait InvWantBus: Send + Sync {
    async fn announce_inventory(
        &self,
        inventory: PubsubInventory,
        source: EventSource,
    ) -> Result<PublishReport>;

    async fn request_want(&self, want: PubsubWant, source: EventSource) -> Result<()>;

    async fn publish_frame(&self, frame: PubsubFrame, source: EventSource)
    -> Result<PublishReport>;
}