Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/nostr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ fn main() -> Result<()> {
.lud16("pay@yukikishimoto.com")
.custom_field("custom_field", "my value");

let event: Event = EventBuilder::metadata(&metadata).finalize(&keys)?;
let event: Event = metadata.finalize(&keys)?;

// New text note
let event: Event = EventBuilder::text_note("Hello from rust-nostr").finalize(&keys)?;

// New POW text note
let difficulty: NonZeroU8 = NonZeroU8::new(16).unwrap();
let unsigned: UnsignedEvent = EventBuilder::text_note("POW text note from rust-nostr").finalize_unsigned(keys.public_key);
let unsigned: UnsignedEvent = EventBuilder::text_note("POW text note from rust-nostr").finalize_unsigned(keys.public_key)?;
let unsigned: UnsignedEvent = unsigned.mine(&SingleThreadPow, difficulty)?;
let event: Event = unsigned.finalize(&keys)?;

Expand Down
2 changes: 1 addition & 1 deletion crates/nostr/examples/nip09.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() -> Result<()> {
.id(event_id)
.reason("these posts were published by accident");

let event: Event = EventBuilder::delete(request).finalize(&keys)?;
let event: Event = request.finalize(&keys)?;
println!("{}", event.as_json());

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/nostr/examples/nip13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() -> Result<()> {

// Build unsigned event
let unsigned: UnsignedEvent =
EventBuilder::text_note(msg_content).finalize_unsigned(keys.public_key);
EventBuilder::text_note(msg_content).finalize_unsigned(keys.public_key)?;

#[cfg(not(feature = "pow-multi-thread"))]
let adapter = SingleThreadPow;
Expand Down
181 changes: 43 additions & 138 deletions crates/nostr/src/event/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::convert::Infallible;
use core::fmt;
use core::ops::Range;

Expand Down Expand Up @@ -37,18 +38,23 @@ impl fmt::Display for WrongKindError {

/// Template that can be converted into a generic [`EventBuilder`].
pub trait EventBuilderTemplate: Sized {
/// Error type
type Error: core::error::Error;

/// Convert into the generic event builder.
fn build(self) -> EventBuilder;
fn build(self) -> Result<EventBuilder, Self::Error>;
}

impl<B> FinalizeUnsignedEvent for B
where
B: EventBuilderTemplate,
{
type Error = B::Error;

#[inline]
fn finalize_unsigned(self, public_key: PublicKey) -> UnsignedEvent {
let builder: EventBuilder = self.build();
builder.finalize_unsigned(public_key)
fn finalize_unsigned(self, public_key: PublicKey) -> Result<UnsignedEvent, Self::Error> {
let builder: EventBuilder = self.build()?;
Ok(builder.finalize_unsigned(public_key).unwrap_infallible())
}
}

Expand All @@ -60,15 +66,18 @@ where
type Error = SignerError;

fn finalize(self, signer: &S) -> Result<Event, Self::Error> {
let builder: EventBuilder = self.build();
let builder: EventBuilder = self.build().map_err(SignerError::backend)?;
builder.finalize(signer)
}
}

/// Template that can asynchronously be converted into a generic [`EventBuilder`].
pub trait EventBuilderTemplateAsync {
/// Error type
type Error: core::error::Error;

/// Convert this typed builder into the generic event builder.
fn build_async<'a>(self) -> BoxedFuture<'a, EventBuilder>
fn build_async<'a>(self) -> BoxedFuture<'a, Result<EventBuilder, Self::Error>>
where
Self: 'a;
}
Expand All @@ -77,8 +86,10 @@ impl<B> EventBuilderTemplateAsync for B
where
B: EventBuilderTemplate + Send,
{
type Error = B::Error;

#[inline]
fn build_async<'a>(self) -> BoxedFuture<'a, EventBuilder>
fn build_async<'a>(self) -> BoxedFuture<'a, Result<EventBuilder, Self::Error>>
where
Self: 'a,
{
Expand All @@ -90,14 +101,22 @@ impl<B> FinalizeUnsignedEventAsync for B
where
B: EventBuilderTemplateAsync + Send,
{
type Error = B::Error;

#[inline]
fn finalize_unsigned_async<'a>(self, public_key: PublicKey) -> BoxedFuture<'a, UnsignedEvent>
fn finalize_unsigned_async<'a>(
self,
public_key: PublicKey,
) -> BoxedFuture<'a, Result<UnsignedEvent, Self::Error>>
where
Self: 'a,
{
Box::pin(async move {
let builder: EventBuilder = self.build_async().await;
builder.finalize_unsigned_async(public_key).await
let builder: EventBuilder = self.build_async().await?;
Ok(builder
.finalize_unsigned_async(public_key)
.await
.unwrap_infallible())
})
}
}
Expand All @@ -115,7 +134,7 @@ where
S: 'a,
{
Box::pin(async move {
let builder: EventBuilder = self.build_async().await;
let builder: EventBuilder = self.build_async().await.map_err(SignerError::backend)?;
builder.finalize_async(signer).await
})
}
Expand Down Expand Up @@ -183,29 +202,6 @@ impl EventBuilder {
self
}

/// Profile metadata
///
/// <https://github.com/nostr-protocol/nips/blob/master/01.md>
///
/// # Example
/// ```rust,no_run
/// use nostr::prelude::*;
///
/// let metadata = Metadata::new()
/// .name("username")
/// .display_name("My Username")
/// .about("Description")
/// .picture(Url::parse("https://example.com/avatar.png").unwrap())
/// .nip05("username@example.com")
/// .lud16("pay@yukikishimoto.com");
///
/// let builder = EventBuilder::metadata(&metadata);
/// ```
#[inline]
pub fn metadata(metadata: &Metadata) -> Self {
Self::new(Kind::Metadata, metadata.as_json())
}

/// Relay list metadata
///
/// <https://github.com/nostr-protocol/nips/blob/master/65.md>
Expand Down Expand Up @@ -416,14 +412,6 @@ impl EventBuilder {
}
}

/// Event deletion request
///
/// <https://github.com/nostr-protocol/nips/blob/master/09.md>
#[inline]
pub fn delete(request: EventDeletionRequest) -> Self {
request.to_event_builder()
}

/// Request to vanish
///
/// <https://github.com/nostr-protocol/nips/blob/master/62.md>
Expand Down Expand Up @@ -1245,88 +1233,6 @@ impl EventBuilder {
Self::new(Kind::UserStatus, content).tags(tags)
}

/// Code Snippets
///
/// <https://github.com/nostr-protocol/nips/blob/master/C0.md>
#[inline]
pub fn code_snippet(snippet: CodeSnippet) -> Self {
snippet.to_event_builder()
}

/// Git Repository Announcement
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_repository_announcement(announcement: GitRepositoryAnnouncement) -> Self {
announcement.to_event_builder()
}

/// Git Issue
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_issue(issue: GitIssue) -> Result<Self, nip34::Error> {
issue.to_event_builder()
}

/// Git Patch
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_patch(patch: GitPatch) -> Result<Self, nip34::Error> {
patch.to_event_builder()
}

/// Git Pull Request
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_pull_request(pull_request: GitPullRequest) -> Result<Self, nip34::Error> {
pull_request.to_event_builder()
}

/// Git Pull Request Update
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_pull_request_update(update: GitPullRequestUpdate) -> Result<Self, nip34::Error> {
update.to_event_builder()
}

/// Git User Grasp List
///
/// <https://github.com/nostr-protocol/nips/blob/master/34.md>
#[inline]
pub fn git_user_grasp_list(grasp_list: GitUserGraspList) -> Self {
grasp_list.to_event_builder()
}

/// Torrent metadata
///
/// <https://github.com/nostr-protocol/nips/blob/master/35.md>
#[inline]
pub fn torrent(metadata: Torrent) -> Self {
metadata.to_event_builder()
}

// TODO: add `torrent_comment`

/// Create a poll
///
/// <https://github.com/nostr-protocol/nips/blob/master/88.md>
#[inline]
pub fn poll(poll: Poll) -> Self {
poll.to_event_builder()
}

/// Create a poll response
///
/// <https://github.com/nostr-protocol/nips/blob/master/88.md>
#[inline]
pub fn poll_response(response: PollResponse) -> Self {
response.to_event_builder()
}

/// Chat message
///
/// <https://github.com/nostr-protocol/nips/blob/master/C7.md>
Expand Down Expand Up @@ -1411,14 +1317,6 @@ impl EventBuilder {

Self::new(Kind::Comment, content).tags(tags)
}

/// Web Bookmark
///
/// <https://github.com/nostr-protocol/nips/blob/master/B0.md>
#[inline]
pub fn web_bookmark(web_bookmark: WebBookmark) -> Self {
web_bookmark.to_event_builder()
}
}

fn has_nostr_event_uri(content: &str, event_id: &EventId) -> bool {
Expand All @@ -1438,23 +1336,30 @@ fn has_nostr_event_uri(content: &str, event_id: &EventId) -> bool {
}

impl FinalizeUnsignedEvent for EventBuilder {
type Error = Infallible;

#[inline]
fn finalize_unsigned(self, public_key: PublicKey) -> UnsignedEvent {
UnsignedEvent {
fn finalize_unsigned(self, public_key: PublicKey) -> Result<UnsignedEvent, Self::Error> {
Ok(UnsignedEvent {
// Not compute event ID, as the user may want POW, so would be an unnecessary computation.
id: None,
pubkey: public_key,
created_at: self.created_at.unwrap_or_else(Timestamp::now),
kind: self.kind,
tags: self.tags,
content: self.content,
}
})
}
}

impl FinalizeUnsignedEventAsync for EventBuilder {
type Error = Infallible;

#[inline]
fn finalize_unsigned_async<'a>(self, public_key: PublicKey) -> BoxedFuture<'a, UnsignedEvent>
fn finalize_unsigned_async<'a>(
self,
public_key: PublicKey,
) -> BoxedFuture<'a, Result<UnsignedEvent, Self::Error>>
where
Self: 'a,
{
Expand All @@ -1470,7 +1375,7 @@ where

fn finalize(self, signer: &S) -> Result<Event, Self::Error> {
let public_key: PublicKey = signer.get_public_key().map_err(SignerError::backend)?;
let unsigned: UnsignedEvent = self.finalize_unsigned(public_key);
let unsigned: UnsignedEvent = self.finalize_unsigned(public_key).unwrap_infallible();
signer.sign_event(unsigned).map_err(SignerError::backend)
}
}
Expand All @@ -1491,7 +1396,7 @@ where
.get_public_key_async()
.await
.map_err(SignerError::backend)?;
let unsigned: UnsignedEvent = self.finalize_unsigned(public_key);
let unsigned: UnsignedEvent = self.finalize_unsigned(public_key).unwrap_infallible();
signer
.sign_event_async(unsigned)
.await
Expand Down
13 changes: 11 additions & 2 deletions crates/nostr/src/event/unsigned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,23 @@ impl From<Event> for UnsignedEvent {

/// Finalize a builder into an unsigned event.
pub trait FinalizeUnsignedEvent: Sized {
/// Error type
type Error: core::error::Error;

/// Build the unsigned event with the supplied public key.
fn finalize_unsigned(self, public_key: PublicKey) -> UnsignedEvent;
fn finalize_unsigned(self, public_key: PublicKey) -> Result<UnsignedEvent, Self::Error>;
}

/// Finalize a builder into an unsigned event asynchronously.
pub trait FinalizeUnsignedEventAsync: Sized {
/// Error type
type Error: core::error::Error;

/// Build the unsigned event with the supplied public key.
fn finalize_unsigned_async<'a>(self, public_key: PublicKey) -> BoxedFuture<'a, UnsignedEvent>
fn finalize_unsigned_async<'a>(
self,
public_key: PublicKey,
) -> BoxedFuture<'a, Result<UnsignedEvent, Self::Error>>
where
Self: 'a;
}
Expand Down
Loading
Loading