update LICENSE and README and new hashtag filter
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "easy-nostr"
|
name = "easy-nostr"
|
||||||
|
authors = ["Bytemalte <[bytemalte@gmail.com]>"]
|
||||||
|
description = "A high-level, developer-friendly Rust library designed to simplify the development of Nostr applications."
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/Bytemalte/easy-nostr"
|
||||||
|
keywords = ["nostr", "crypto", "social", "decentralized"]
|
||||||
|
categories = ["cryptography", "network-programming", "web-programming"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nostr-sdk = { version = "0.44.1", features = ["all-nips", "nip44"] }
|
nostr-sdk = { version = "0.44.1", features = ["all-nips", "nip44"] }
|
||||||
|
|||||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) [2026] [Bytemalte]
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
209
README.md
209
README.md
@@ -1,18 +1,40 @@
|
|||||||
# EasyNostr
|
# 🌌 EasyNostr
|
||||||
|
|
||||||
A simple and functional Rust crate for building Nostr applications. This library handles the complexity of keys, relays, and protocol details (NIPs), giving you easy-to-use functions for a social media app.
|
[](https://www.rust-lang.org/)
|
||||||
|
[](https://nostr.com/)
|
||||||
|
|
||||||
## Features
|
**EasyNostr** is a high-level, developer-friendly Rust library designed to simplify the development of Nostr applications. It wraps the powerful `nostr-sdk` to provide a clean, intuitive API for common operations like identity management, social feeds, and encrypted messaging.
|
||||||
- **Identity**: Easy management of keys (nsec/npub).
|
|
||||||
- **Social Feed**: View timeline of friends or global random posts.
|
|
||||||
- **Posting**: Publish text notes (Kind 1).
|
|
||||||
- **Contacts**: Follow users and retrieve your contact list.
|
|
||||||
- **Direct Messages**: Send and receive encrypted private messages (NIP-17 & NIP-04).
|
|
||||||
|
|
||||||
## Getting Started
|
---
|
||||||
|
|
||||||
### 1. Initialize the Client
|
## 🚀 Key Features
|
||||||
First, you need to create an instance of `EasyNostr` using your secret key (nsec).
|
|
||||||
|
* **Identity Management**: Simple handling of keys (nsec/npub).
|
||||||
|
* **Social Connectivity**: Follow users and manage contact lists.
|
||||||
|
* **Rich Feeds**: Access follow-based timelines, global discovery, and hashtag-based searches.
|
||||||
|
* **Encrypted Messaging**: Secure NIP-17 direct messages.
|
||||||
|
* **Extensible Architecture**: Clean separation between protocol logic (NIPs) and high-level functions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
Add `easy-nostr` and its core dependencies to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
easy-nostr = { path = "." } # Use the crate path
|
||||||
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
|
anyhow = "1.0.100"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Usage Guide
|
||||||
|
|
||||||
|
### 1. Initialization & Connection
|
||||||
|
|
||||||
|
Create a new instance and connect to your preferred relays.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use easy_nostr::EasyNostr;
|
use easy_nostr::EasyNostr;
|
||||||
@@ -20,127 +42,100 @@ use anyhow::Result;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// Your secret key (nsec)
|
// Initialize with your private key (nsec)
|
||||||
let my_secret_key = "nsec1...";
|
let secret_key = "nsec1...";
|
||||||
|
let en = EasyNostr::new(secret_key).await?;
|
||||||
|
|
||||||
// Initialize client
|
// Add relays to connect to the network
|
||||||
let client = EasyNostr::new(my_secret_key).await?;
|
en.add_relays(vec![
|
||||||
|
|
||||||
// Connect to Relays
|
|
||||||
client.add_relays(vec![
|
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
"wss://nos.lol",
|
"wss://nos.lol",
|
||||||
"wss://relay.primal.net"
|
"wss://relay.primal.net"
|
||||||
]).await?;
|
]).await?;
|
||||||
|
|
||||||
println!("Connected and ready!");
|
println!("Connected to Nostr!");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
### 📝 Publishing Content
|
||||||
|
|
||||||
## Capabilities & Usage
|
Post a simple text note (Kind 1) to the network.
|
||||||
|
|
||||||
### 📝 Publishing Posts
|
|
||||||
Post a simple text message to the network.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let event_id = client.post_text("Hello Nostr world!").await?;
|
let event_id = en.post_text("Building with EasyNostr is awesome!").await?;
|
||||||
println!("Posted! ID: {}", event_id.to_bech32()?);
|
println!("Successfully posted! Event ID: {}", event_id);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 📰 Reading Feeds
|
### 📰 Social Feeds
|
||||||
You can read posts from people you follow (Timeline) or random posts from the network.
|
|
||||||
|
#### Timeline (Followed Users)
|
||||||
|
Fetch posts from a specific list of public keys.
|
||||||
|
|
||||||
**Get Timeline (Followed Users):**
|
|
||||||
```rust
|
```rust
|
||||||
// List of public keys (npubs) you want to see posts from
|
let follow_list = vec!["npub1...".to_string(), "npub2...".to_string()];
|
||||||
let following = vec!["npub1...", "npub1..."];
|
match en.get_timeline(follow_list).await {
|
||||||
|
Ok(posts) => {
|
||||||
let posts = client.get_timeline(following).await?;
|
for post in posts {
|
||||||
|
println!("@{} says: {}", post.author, post.content);
|
||||||
for post in posts {
|
}
|
||||||
println!("@{} wrote: {}", post.author.to_bech32()?, post.content);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Get Global Feed (Random/Recent):**
|
|
||||||
```rust
|
|
||||||
let random_posts = client.get_random_posts().await?;
|
|
||||||
|
|
||||||
for post in random_posts {
|
|
||||||
println!("New Post: {}", post.content);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**The `Post` Structure:**
|
|
||||||
When you get posts, you receive a `Post` struct:
|
|
||||||
- `post.id`: The unique Event ID.
|
|
||||||
- `post.author`: The PublicKey of the author.
|
|
||||||
- `post.content`: The text content.
|
|
||||||
- `post.created_at`: The timestamp.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 👥 Managing Contacts (Followers)
|
|
||||||
Manage who you follow.
|
|
||||||
|
|
||||||
**Follow a User:**
|
|
||||||
```rust
|
|
||||||
let jack_dorsey = "npub1sg6plzptd64u62a878hep2kd8856nmmhd0x479jp6bir725uqqks698teq";
|
|
||||||
// Context: (NPub, Optional Nickname)
|
|
||||||
client.create_contact(jack_dorsey, Some("Jack".to_string())).await?;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Get Your Contact List:**
|
|
||||||
```rust
|
|
||||||
let my_contacts = client.get_contacts().await?;
|
|
||||||
|
|
||||||
for contact in my_contacts {
|
|
||||||
println!("Following: {:?}", contact.public_key.to_bech32()?);
|
|
||||||
if let Some(alias) = &contact.alias {
|
|
||||||
println!(" - Alias: {}", alias);
|
|
||||||
}
|
}
|
||||||
|
Err(e) => eprintln!("Failed to load timeline: {}", e),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Discovery (Global Feed)
|
||||||
|
Get recent random posts from connected relays.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let global_posts = en.get_random_posts().await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hashtag Search (NIP-12)
|
||||||
|
Search for posts containing specific hashtags.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let tags = vec!["bitcoin".to_string(), "rust".to_string()];
|
||||||
|
let filtered_posts = en.get_posts_by_hashtags(tags).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 👥 Contacts & Following
|
||||||
|
|
||||||
|
#### Follow a User
|
||||||
|
```rust
|
||||||
|
en.create_contact("npub1...", Some("Alice".to_string())).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Retrieve Contact List
|
||||||
|
```rust
|
||||||
|
let contacts = en.get_contacts().await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔒 Private Messaging (NIP-17)
|
||||||
|
|
||||||
|
#### Send a Message
|
||||||
|
```rust
|
||||||
|
en.send_private_message("npub1...", "Hello, this is a secret!").await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Retrieve Conversations
|
||||||
|
```rust
|
||||||
|
let history = en.get_private_messages("npub1...").await?;
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🔒 Direct Messages (DMs)
|
## 📂 Project Structure
|
||||||
Send and receive encrypted private chats. Supports modern GiftWraps (NIP-17).
|
|
||||||
|
|
||||||
**Send a DM:**
|
| Directory | Purpose |
|
||||||
```rust
|
| :--- | :--- |
|
||||||
let friend_npub = "npub1...";
|
| `src/lib.rs` | Main entry point and public `EasyNostr` interface. |
|
||||||
client.send_private_message(friend_npub, "Hey, this is secret!").await?;
|
| `src/functions/` | Implementation of high-level features (feeds, messaging, etc.). |
|
||||||
```
|
| `src/nips/` | Protocol-level logic and data structures categorized by NIP. |
|
||||||
|
| `src/bin/` | Utility binaries and examples. |
|
||||||
**Read DMs:**
|
|
||||||
```rust
|
|
||||||
let friend_npub = "npub1...";
|
|
||||||
let messages = client.get_private_messages(friend_npub).await?;
|
|
||||||
|
|
||||||
for msg in messages {
|
|
||||||
let direction = if msg.is_incoming { "Received" } else { "Sent" };
|
|
||||||
println!("[{}] {}", direction, msg.content);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**The `Message` Structure:**
|
|
||||||
- `msg.sender`: PublicKey of the sender.
|
|
||||||
- `msg.content`: Decrypted text.
|
|
||||||
- `msg.is_incoming`: `true` if you received it, `false` if you sent it.
|
|
||||||
- `msg.created_at`: Use `msg.created_at.as_secs()` to get the unix timestamp.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Dependencies
|
## ⚖️ License
|
||||||
Ensure you have the following in your `Cargo.toml`. `easy-nostr` re-exports most things you need, but you might need `anyhow` and `tokio`.
|
|
||||||
|
|
||||||
```toml
|
Distributed under the MIT License. See `LICENSE` for more information.
|
||||||
[dependencies]
|
|
||||||
nostr-sdk = { version = "0.44.1", features = ["all-nips", "nip44"] }
|
|
||||||
tokio = { version = "1.48.0", features = ["full"] }
|
|
||||||
anyhow = "1.0.100"
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
Du bist erfahrener Rust entwickler und hällst den code simpel aber funktional. Achte darauf die richtigen versionen zu verwenden: nostr-sdk = { version = "0.44.1", features = ["all-nips", "nip44"] }
|
|
||||||
tokio = { version = "1.48.0", features = ["full"] }
|
|
||||||
secp256k1 = "0.27"
|
|
||||||
anyhow = "1.0.100"
|
|
||||||
Kommentiere alles in einfachem English im code fürs verständnis. Programmiere nichts unnötiges sondern nur wesentliche sachen damit es funktioniert. Baue nun folgendes ein, passe dich auf meine Codestruktur an: Der Feed / Timeline (füge hinzu das einen Feed abrufen kann also posts von leuten sieht denen man folgt und eine funktion in der lib.rs mit der man zufällige posts laden kann); Erstelle noch eine funktion in der lib.rs das man Text posts selber machen kann. Teile alles wieder auf in @src/nips und @src/functions und die lib.rs @lib.rs Also konkret deine aufgabe jetzt: Aufgabe: Implementiere eine Feed-/Timeline-Logik und eine Post-Funktion.
|
|
||||||
|
|
||||||
lib.rs: Zentrale Einstiegspunkte.
|
|
||||||
|
|
||||||
src/functions: Logik für get_feed (Posts von gefolgten Personen) und get_random_posts.
|
|
||||||
|
|
||||||
src/nips: Definition der Datenstrukturen (Post-Typen).
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
Funktion zum Erstellen eines Text-Posts.
|
|
||||||
|
|
||||||
Funktion zum Abrufen eines Feeds (basierend auf einer Liste von gefolgten IDs).
|
|
||||||
|
|
||||||
Funktion für zufällige Posts.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
warning: use of deprecated method `nostr_sdk::Timestamp::as_u64`: Use `as_secs` instead
|
|
||||||
--> src/bin/testall.rs:40:63
|
|
||||||
|
|
|
||||||
40 | ...w().as_u64());
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= note: `#[warn(deprecated)]` on by default
|
|
||||||
|
|
||||||
warning: `easy-nostr` (bin "testall") generated 1 warning
|
|
||||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s
|
|
||||||
Running `target/debug/testall`
|
|
||||||
=== EasyNostr Production Test Suite ===
|
|
||||||
[INFO] Identity: npub1jx2cnrlnpvy9gxgfnkqf30l0u3jkgjmp76jcvgxw5uuf5lqynduqz9n2me
|
|
||||||
|
|
||||||
[STEP 1] Connecting to Relays...
|
|
||||||
[OK] Connected.
|
|
||||||
|
|
||||||
[STEP 2] Following Self (for robust timeline testing)...
|
|
||||||
[OK] Followed self.
|
|
||||||
|
|
||||||
[STEP 3] Publishing Post...
|
|
||||||
[OK] Posted: note10xlp2za0p0ug3v49ggve2gv2lzfmgltzk84a7qkueskeau9kj5nshcfu20
|
|
||||||
|
|
||||||
[STEP 4] verifying Timeline (expecting own post)...
|
|
||||||
[OK] Found our post in timeline after 2s!
|
|
||||||
|
|
||||||
[STEP 5] Testing Direct Messages...
|
|
||||||
... attempt 1/5: DM not yet visible...
|
|
||||||
... attempt 2/5: DM not yet visible...
|
|
||||||
... attempt 3/5: DM not yet visible...
|
|
||||||
... attempt 4/5: DM not yet visible...
|
|
||||||
... attempt 5/5: DM not yet visible...
|
|
||||||
[ERR] DM propagation failed.
|
|
||||||
|
|
||||||
=== Test Complete ===
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
Compiling easy-nostr v0.1.0 (/home/malxte/Documents/Programming/Rust/Crates/easy-nostr)
|
|
||||||
warning: use of deprecated method `nostr_sdk::Timestamp::as_u64`: Use `as_secs` instead
|
|
||||||
--> src/bin/testall.rs:40:63
|
|
||||||
|
|
|
||||||
40 | let secret_code = format!("Test Run {}", Timestamp::now().as_u64());
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= note: `#[warn(deprecated)]` on by default
|
|
||||||
|
|
||||||
warning: `easy-nostr` (bin "testall") generated 1 warning
|
|
||||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.40s
|
|
||||||
Running `target/debug/testall`
|
|
||||||
=== EasyNostr Production Test Suite ===
|
|
||||||
[INFO] Identity: npub1tfqs84ttgcw8z424dsrzzkchmee9s22hzpahxxxmyrg3z82zwmusmq4aga
|
|
||||||
|
|
||||||
[STEP 1] Connecting to Relays...
|
|
||||||
[OK] Connected.
|
|
||||||
|
|
||||||
[STEP 2] Following Self (for robust timeline testing)...
|
|
||||||
[OK] Followed self.
|
|
||||||
|
|
||||||
[STEP 3] Publishing Post...
|
|
||||||
[OK] Posted: note1p79vn2myyd29adw3dk0t0vuxk50ng0fkqk4yhhq34u085j4k65rqq40c0q
|
|
||||||
|
|
||||||
[STEP 4] verifying Timeline (expecting own post)...
|
|
||||||
[OK] Found our post in timeline after 2s!
|
|
||||||
|
|
||||||
[STEP 5] Testing Direct Messages...
|
|
||||||
[OK] Found DM after 2s!
|
|
||||||
|
|
||||||
=== Test Complete ===
|
|
||||||
35
src/functions/hashtags.rs
Normal file
35
src/functions/hashtags.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use crate::nips::nip01::Post;
|
||||||
|
use crate::nips::nip12;
|
||||||
|
use anyhow::Result;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Fetches posts by one or more hashtags.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `client` - The Nostr client.
|
||||||
|
/// * `hashtags` - A list of hashtags to search for.
|
||||||
|
pub async fn get_posts_by_hashtags<S>(client: &Client, hashtags: Vec<S>) -> Result<Vec<Post>>
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
let filter = nip12::create_hashtag_filter(hashtags);
|
||||||
|
|
||||||
|
let timeout = Duration::from_secs(10);
|
||||||
|
let events = client.fetch_events(filter, timeout).await?;
|
||||||
|
|
||||||
|
let mut posts: Vec<Post> = events
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| Post {
|
||||||
|
id: e.id,
|
||||||
|
author: e.pubkey,
|
||||||
|
content: e.content.clone(),
|
||||||
|
created_at: e.created_at,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort by newest first
|
||||||
|
posts.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
||||||
|
|
||||||
|
Ok(posts)
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod create_contact;
|
pub mod create_contact;
|
||||||
pub mod feed;
|
pub mod feed;
|
||||||
pub mod get_contacts;
|
pub mod get_contacts;
|
||||||
|
pub mod hashtags;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod new;
|
pub mod new;
|
||||||
pub mod publish;
|
pub mod publish;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ use anyhow::Result;
|
|||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
// Wir importieren die Funktionen, um Tipparbeit zu sparen
|
// Wir importieren die Funktionen, um Tipparbeit zu sparen
|
||||||
use crate::functions::{create_contact, feed, get_contacts, messages, new, publish, relays};
|
use crate::functions::{
|
||||||
|
create_contact, feed, get_contacts, hashtags, messages, new, publish, relays,
|
||||||
|
};
|
||||||
use crate::nips::nip01::Post;
|
use crate::nips::nip01::Post;
|
||||||
use crate::nips::nip17::Message;
|
use crate::nips::nip17::Message;
|
||||||
|
|
||||||
@@ -63,4 +65,9 @@ impl EasyNostr {
|
|||||||
pub async fn get_random_posts(&self) -> Result<Vec<Post>> {
|
pub async fn get_random_posts(&self) -> Result<Vec<Post>> {
|
||||||
feed::get_random_posts(&self.client).await
|
feed::get_random_posts(&self.client).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lädt Posts nach Hashtags (z.B. "bitcoin", "rust")
|
||||||
|
pub async fn get_posts_by_hashtags(&self, hashtags: Vec<String>) -> Result<Vec<Post>> {
|
||||||
|
hashtags::get_posts_by_hashtags(&self.client, hashtags).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod nip01;
|
pub mod nip01;
|
||||||
pub mod nip17;
|
|
||||||
pub mod nip02;
|
pub mod nip02;
|
||||||
|
pub mod nip12;
|
||||||
|
pub mod nip17;
|
||||||
|
|||||||
13
src/nips/nip12.rs
Normal file
13
src/nips/nip12.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
|
/// Creates a filter for Kind 1 posts matching specific hashtags.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `hashtags` - A list of hashtags to filter for (without the #).
|
||||||
|
pub fn create_hashtag_filter<S>(hashtags: Vec<S>) -> Filter
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
let tags: Vec<String> = hashtags.into_iter().map(|s| s.into()).collect();
|
||||||
|
Filter::new().kind(Kind::TextNote).hashtags(tags).limit(50)
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
Compiling easy-nostr v0.1.0 (/home/malxte/Documents/Programming/Rust/Crates/easy-nostr)
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
|
||||||
--> src/bin/testall.rs:12:16
|
|
||||||
|
|
|
||||||
12 | let nsec = keys.secret_key()?.to_bech32()?;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `&nostr_sdk::SecretKey`
|
|
||||||
|
|
|
||||||
= help: the trait `Try` is not implemented for `&nostr_sdk::SecretKey`
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
|
||||||
error: could not compile `easy-nostr` (bin "testall") due to 1 previous error
|
|
||||||
Reference in New Issue
Block a user