Structured files/directories and nip01, nip02, nip17 implementation
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
1790
Cargo.lock
generated
Normal file
1790
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "easy-nostr"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nostr-sdk = { version = "0.44.1", features = ["all-nips", "nip44"] }
|
||||||
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
|
secp256k1 = "0.27"
|
||||||
|
anyhow = "1.0.100"
|
||||||
24
src/functions/create_contact.rs
Normal file
24
src/functions/create_contact.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use anyhow::{Context, Result};
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use crate::functions::get_contacts; // Wir nutzen die Logik von nebenan
|
||||||
|
|
||||||
|
pub async fn create_contact(client: &Client, npub: &str, nickname: Option<String>) -> Result<EventId> {
|
||||||
|
let new_pk = PublicKey::parse(npub).context("Ungültiger npub")?;
|
||||||
|
|
||||||
|
// 1. Liste laden (über die ausgelagerte Funktion)
|
||||||
|
let mut current_contacts = get_contacts::get_contacts(client).await?;
|
||||||
|
|
||||||
|
// 2. Alten Eintrag löschen (Update)
|
||||||
|
current_contacts.retain(|c| c.public_key != new_pk);
|
||||||
|
|
||||||
|
// 3. Neuen Kontakt hinzufügen
|
||||||
|
let mut new_contact = Contact::new(new_pk);
|
||||||
|
new_contact.alias = nickname;
|
||||||
|
current_contacts.push(new_contact);
|
||||||
|
|
||||||
|
// 4. Senden
|
||||||
|
let builder = EventBuilder::contact_list(current_contacts);
|
||||||
|
let output = client.send_event_builder(builder).await?;
|
||||||
|
|
||||||
|
Ok(*output.id())
|
||||||
|
}
|
||||||
26
src/functions/get_contacts.rs
Normal file
26
src/functions/get_contacts.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use nostr_sdk::nostr::TagStandard;
|
||||||
|
use crate::nips::nip02;
|
||||||
|
|
||||||
|
pub async fn get_contacts(client: &Client) -> Result<Vec<Contact>> {
|
||||||
|
let event_opt = nip02::get_contact_list_event(client).await?;
|
||||||
|
|
||||||
|
match event_opt {
|
||||||
|
Some(event) => {
|
||||||
|
let mut contacts = Vec::new();
|
||||||
|
for tag in event.tags {
|
||||||
|
if let Some(TagStandard::PublicKey { public_key, relay_url, alias, .. }) = tag.as_standardized() {
|
||||||
|
// Werte kopieren/klonen (Ownership Fix)
|
||||||
|
let mut contact = Contact::new(*public_key);
|
||||||
|
contact.relay_url = relay_url.clone();
|
||||||
|
contact.alias = alias.clone();
|
||||||
|
|
||||||
|
contacts.push(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(contacts)
|
||||||
|
}
|
||||||
|
None => Ok(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/functions/messages.rs
Normal file
8
src/functions/messages.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use crate::nips::nip17;
|
||||||
|
|
||||||
|
pub async fn send_private_message(client: &Client, receiver_pubkey: &str, message: &str) -> Result<EventId> {
|
||||||
|
let receiver = PublicKey::parse(receiver_pubkey)?;
|
||||||
|
nip17::send_dm(client, receiver, message).await
|
||||||
|
}
|
||||||
5
src/functions/mod.rs
Normal file
5
src/functions/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod new;
|
||||||
|
pub mod messages;
|
||||||
|
pub mod relays;
|
||||||
|
pub mod get_contacts;
|
||||||
|
pub mod create_contact;
|
||||||
8
src/functions/new.rs
Normal file
8
src/functions/new.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
|
pub async fn new_client(private_key: &str) -> Result<Client> {
|
||||||
|
let keys = Keys::parse(private_key)?;
|
||||||
|
let client = Client::new(keys);
|
||||||
|
Ok(client)
|
||||||
|
}
|
||||||
10
src/functions/relays.rs
Normal file
10
src/functions/relays.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
|
pub async fn add_relays(client: &Client, urls: Vec<&str>) -> Result<()> {
|
||||||
|
for url in urls {
|
||||||
|
client.add_relay(url.to_string()).await?;
|
||||||
|
}
|
||||||
|
client.connect().await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
41
src/lib.rs
Normal file
41
src/lib.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
pub mod nips;
|
||||||
|
pub mod functions; // Das neue Modul registrieren
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
|
// Wir importieren die Funktionen, um Tipparbeit zu sparen
|
||||||
|
use crate::functions::{new, messages, relays, get_contacts, create_contact};
|
||||||
|
|
||||||
|
pub struct EasyNostr {
|
||||||
|
client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EasyNostr {
|
||||||
|
/// Erstellt eine neue Instanz
|
||||||
|
pub async fn new(private_key: &str) -> Result<Self> {
|
||||||
|
// Aufruf der Logik in functions/new.rs
|
||||||
|
let client = new::new_client(private_key).await?;
|
||||||
|
Ok(Self { client })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sendet eine verschlüsselte DM (NIP-17 Wrapper)
|
||||||
|
pub async fn send_private_message(&self, receiver_pubkey: &str, message: &str) -> Result<EventId> {
|
||||||
|
messages::send_private_message(&self.client, receiver_pubkey, message).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fügt Relays hinzu und verbindet
|
||||||
|
pub async fn add_relays(&self, urls: Vec<&str>) -> Result<()> {
|
||||||
|
relays::add_relays(&self.client, urls).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lädt die Kontaktliste (NIP-02)
|
||||||
|
pub async fn get_contacts(&self) -> Result<Vec<Contact>> {
|
||||||
|
get_contacts::get_contacts(&self.client).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Erstellt oder aktualisiert einen Kontakt
|
||||||
|
pub async fn create_contact(&self, npub: &str, nickname: Option<String>) -> Result<EventId> {
|
||||||
|
create_contact::create_contact(&self.client, npub, nickname).await
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/nips/mod.rs
Normal file
3
src/nips/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod nip01;
|
||||||
|
pub mod nip17;
|
||||||
|
pub mod nip02;
|
||||||
9
src/nips/nip01.rs
Normal file
9
src/nips/nip01.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use anyhow::Result; // <--- Hinzufügen
|
||||||
|
|
||||||
|
// Das Result hier bezieht sich jetzt auf anyhow::Result
|
||||||
|
pub async fn publish_text(client: &Client, content: &str) -> Result<EventId> {
|
||||||
|
let builder = EventBuilder::text_note(content);
|
||||||
|
let output = client.send_event_builder(builder).await?;
|
||||||
|
Ok(*output.id())
|
||||||
|
}
|
||||||
23
src/nips/nip02.rs
Normal file
23
src/nips/nip02.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Ruft das letzte Kontaktlisten-Event (Kind 3) für den Benutzer ab.
|
||||||
|
pub async fn get_contact_list_event(client: &Client) -> Result<Option<Event>> {
|
||||||
|
let signer = client.signer().await?;
|
||||||
|
|
||||||
|
// FIX: Die Methode heißt jetzt get_public_key()
|
||||||
|
let public_key = signer.get_public_key().await?;
|
||||||
|
|
||||||
|
let filter = Filter::new()
|
||||||
|
.author(public_key)
|
||||||
|
.kind(Kind::ContactList)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let timeout = Duration::from_secs(10);
|
||||||
|
|
||||||
|
// fetch_events nimmt einen einzelnen Filter
|
||||||
|
let events = client.fetch_events(filter, timeout).await?;
|
||||||
|
|
||||||
|
Ok(events.into_iter().next())
|
||||||
|
}
|
||||||
7
src/nips/nip17.rs
Normal file
7
src/nips/nip17.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use anyhow::Result; // <--- Hinzufügen
|
||||||
|
|
||||||
|
pub async fn send_dm(client: &Client, receiver: PublicKey, message: &str) -> Result<EventId> {
|
||||||
|
let output = client.send_private_msg(receiver, message, None).await?;
|
||||||
|
Ok(*output.id())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user