An ergonomic, Nostr API Client for Rust.
[dependencies] nostr_rust = "*"And then the code:
use std::{ str::FromStr, sync::{Arc, Mutex}, thread, }; use nostr_rust::{nostr_client::Client, req::ReqFilter, Identity, Message, events::extract_events_ws, utils::parse_content_tags}; fn handle_message(relay_url: &String, message: &Message) -> Result<(), String> { println!("Received message from {}: {:?}", relay_url, message); let events = extract_events_ws(message); println!("Events: {:?}", events); Ok(()) } fn main() { let my_identity = Identity::from_str("your private key as hex string") .unwrap(); let nostr_client = Arc::new(Mutex::new( Client::new(vec!["wss://relay.nostr.info"]).unwrap(), )); // Run a new thread to handle messages let nostr_clone = nostr_client.clone(); let handle_thread = thread::spawn(move || { println!("Listening..."); let events = nostr_clone.lock().unwrap().next_data().unwrap(); for (relay_url, message) in events.iter() { handle_message(relay_url, message).unwrap(); } }); // Change metadata nostr_client .lock() .unwrap() .set_metadata( &my_identity, Some("Rust Nostr Client test account"), Some("Hello Nostr! #5"), None, None, 0, ) .unwrap(); // Subscribe to my last text note let subscription_id = nostr_client .lock() .unwrap() .subscribe(vec![ReqFilter { ids: None, authors: Some(vec![ "884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string(), ]), kinds: None, e: None, p: None, since: None, until: None, limit: Some(1), }]) .unwrap(); // Unsubscribe nostr_client .lock() .unwrap() .unsubscribe(&subscription_id) .unwrap(); // You can use the parse content tags method to get the content and the tags from a string // let tags = parse_content_tags("hello #world", vec![], Some(nostr_rust::DEFAULT_HASHTAG), true, true); // assert_eq!(tags.content, "hello #world"); // assert_eq!(tags.tags, vec![vec!["t", "world"]]); // Publish a text note nostr_client .lock() .unwrap() .publish_text_note(&my_identity, "Hello Nostr! :)", &[], 0) .unwrap(); // Publish a proof of work text note with a difficulty target of 15 nostr_client .lock() .unwrap() .publish_text_note(&my_identity, "Hello Nostr! :)", &[], 15) .unwrap(); // Wait for the thread to finish handle_thread.join().unwrap(); } ## Async feature If you want to use the async version of the client, you can enable the `async` feature: ```toml [dependencies] nostr_rust = { version = "*", features = ["async"] }| NIP | Supported | Client Version | Description |
|---|---|---|---|
| 01 | ✅ | 0.1.0 | Basic protocol flow description |
| 02 | ✅ | 0.3.0 | Contact List and Petnames |
| 03 | ❌ | Not supported | OpenTimestamps Attestations for Events |
| 04 | ✅ | 0.6.0 | Encrypted Direct Message |
| 05 | ✅ | 0.15.0 | Mapping Nostr keys to DNS-based internet identifiers |
| 06 | ❌ | Not supported | Basic key derivation from mnemonic seed phrase |
| 07 | Not concerned | Not supported | window.nostr capability for web browsers |
| 08 | Not concerned | Not supported | Handling Mentions |
| 09 | ✅ | 0.5.0 | Event Deletion |
| 10 | Not concerned | Not supported | Conventions for clients' use of e and p tags in text events. |
| 11 | ✅ | 0.9.0 | Relay Information Document |
| 12 | ❌ | Not supported | Generic Tag Queries |
| 13 | ✅ | 0.8.0 | Proof of Work |
| 14 | Not concerned | Not supported | Subject tag in text events. |
| 15 | ❌ | Not supported | End of Stored Events Notice |
| 16 | ✅ | 0.13.0 | Event Treatment |
| 22 | ❌ | Not supported | Event created_at Limits |
| 25 | ✅ | 0.4.0 | Reactions |
| 28 | ❌ | Not supported | Public Chat |
Licensed under MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)