Rust去中心化社交协议库nostr-sdk的使用,支持Nostr协议的客户端开发与事件交互

Rust去中心化社交协议库nostr-sdk的使用,支持Nostr协议的客户端开发与事件交互

Nostr SDK

这是一个用Rust编写的高层Nostr客户端库。如果你正在编写一个典型的Nostr客户端或机器人,这个库很可能就是你需要的。

快速开始

use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

use nostr_sdk::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    // 生成新的随机密钥
    let keys = Keys::generate();

    // 或者使用已有的密钥(从hex或bech32格式)
    let keys = Keys::parse("hex-or-bech32-secret-key")?;

    // 显示bech32格式的公钥
    let bech32_pubkey: String = keys.public_key().to_bech32()?;
    println!("Bech32 PubKey: {}", bech32_pubkey);

    // 配置客户端使用代理连接.onion中继
    let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9050));
    let connection: Connection = Connection::new()
        .proxy(addr) // 使用`.embedded_tor()`替代以启用嵌入式tor客户端(需要`tor`特性)
        .target(ConnectionTarget::Onion);
    let opts = ClientOptions::new().connection(connection);

    // 创建带有自定义选项的新客户端
    let client = Client::builder().signer(keys.clone()).opts(opts).build();

    // 添加中继
    client.add_relay("wss://relay.damus.io").await?;
    client.add_relay("ws://jgqaglhautb4k6e6i2g34jakxiemqp6z4wynlirltuukgkft2xuglmqd.onion").await?;
    
    // 添加只读中继
    client.add_read_relay("wss://relay.nostr.info").await?;

    // 连接到中继
    client.connect().await;

    let metadata = Metadata::new()
        .name("username")
        .display_name("My Username")
        .about("Description")
        .picture(Url::parse("https://example.com/avatar.png")?)
        .banner(Url::parse("https://example.com/banner.png")?)
        .nip05("username@example.com")
        .lud16("pay@yukikishimoto.com")
        .custom_field("custom_field", "my value");

    // 更新元数据
    client.set_metadata(&metadata).await?;

    // 发布一条文本笔记
    let builder = EventBuilder::text_note("My first text note from rust-nostr!");
    client.send_event_builder(builder).await?;

    // 创建一条POW文本笔记
    let builder = EventBuilder::text_note("POW text note from nostr-sdk").pow(20);
    client.send_event_builder(builder).await?; // 发送到所有中继
    // client.send_event_builder_to(["wss://relay.damus.io"], builder).await?; // 发送到特定中继

    Ok(())
}

WASM支持

这个库支持wasm32目标。在macOS上,你需要安装llvm:

brew install llvm
LLVM_PATH=$(brew --prefix llvm)
AR="${LLVM_PATH}/bin/llvm-ar" CC="${LLVM_PATH}/bin/clang" cargo build --target wasm32-unknown-unknown

注意: 目前nip03特性不支持WASM。

特性标志

以下是可用的特性标志:

特性 默认 描述
tor 启用嵌入式tor客户端支持
lmdb 启用LMDB存储后端
ndb 启用nostrdb存储后端
indexeddb 启用Web的IndexedDb存储后端
all-nips 启用所有NIPs
nip03 启用NIP-03: 事件的时间戳证明
nip04 启用NIP-04: 加密直接消息
nip06 启用NIP-06: 从助记词派生基本密钥
nip44 启用NIP-44: 加密载荷(版本化)
nip47 启用NIP-47: Nostr钱包连接
nip49 启用NIP-49: 私钥加密
nip57 启用NIP-57: 打赏
nip59 启用NIP-59: 礼物包装

状态

这个库处于ALPHA状态,已实现的功能通常可以工作,但API可能会有重大变更。

许可证

这个项目采用MIT软件许可证。

完整示例代码

基于上述内容,这里是一个更完整的Nostr客户端开发示例:

use nostr_sdk::prelude::*;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<()> {
    // 1. 密钥管理
    let keys = Keys::generate(); // 生成新密钥
    println!("公钥: {}", keys.public_key().to_bech32()?);
    
    // 2. 客户端配置
    let opts = ClientOptions::new()
        .send_timeout(Some(Duration::from_secs(10))) // 设置超时
        .wait_for_send(true); // 等待发送确认
    
    let client = Client::builder()
        .signer(keys.clone())
        .opts(opts)
        .build();
    
    // 3. 连接中继
    client.add_relay("wss://relay.damus.io").await?;
    client.add_relay("wss://nostr-relay.wlvs.space").await?;
    client.connect().await;
    
    // 4. 发布元数据
    let metadata = Metadata::new()
        .name("rust-nostr-example")
        .display_name("Rust Nostr示例")
        .about("使用nostr-sdk的示例客户端");
    client.set_metadata(&metadata).await?;
    
    // 5. 发布文本笔记
    let event_id = client
        .publish_text_note("Hello from Rust Nostr SDK!", &[])
        .await?;
    println!("发布的事件ID: {}", event_id);
    
    // 6. 订阅和接收事件
    let subscription = Filter::new()
        .author(keys.public_key())
        .limit(10);
    
    client.subscribe(vec![subscription]).await;
    
    let mut notifications = client.notifications();
    while let Ok(notification) = notifications.recv().await {
        if let RelayPoolNotification::Event(_url, event) = notification {
            println!("收到新事件: {:?}", event);
        }
    }
    
    Ok(())
}

这个示例展示了:

  1. 密钥生成和管理
  2. 客户端配置
  3. 中继连接
  4. 元数据发布
  5. 文本笔记发布
  6. 事件订阅和接收

你可以根据需要扩展这个基本框架,添加更多Nostr协议功能。


1 回复

以下是基于您提供的内容整理的Rust去中心化社交协议库nostr-sdk使用指南,包含完整示例代码:

Rust去中心化社交协议库nostr-sdk使用指南

简介

nostr-sdk是一个Rust实现的Nostr协议库,用于开发支持Nostr协议的客户端应用。Nostr是一个简单的、去中心化的社交网络协议,基于事件(event)和密钥对(key pair)运作。

主要功能

  • 创建和管理Nostr密钥对
  • 构建和解析Nostr事件
  • 与中继服务器(relay)交互
  • 处理Nostr协议的各种消息类型

安装

在Cargo.toml中添加依赖:

[dependencies]
nostr-sdk = "0.10"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"

完整示例代码

1. 密钥管理和基本事件发送

use nostr_sdk::{Keys, Event, Client};
use std::time::Duration;

#[tokio::main]
async fn main() {
    // 1. 生成密钥对
    let keys = Keys::generate();
    println!("生成的私钥: {}", keys.secret_key().unwrap());
    println!("生成的公钥: {}", keys.public_key());

    // 2. 创建文本事件
    let event = Event::new_text_note(&keys, "这是我的第一条Nostr消息!").unwrap();
    println!("创建的事件: {:?}", event);

    // 3. 连接中继并发送事件
    let client = Client::new();
    client.add_relay("wss://relay.damus.io").await.unwrap();
    client.connect().await;
    
    // 发送事件
    match client.send_event(event).await {
        Ok(_) => println!("事件发送成功!"),
        Err(e) => println!("发送失败: {:?}", e),
    }

    // 等待5秒后断开连接
    tokio::time::sleep(Duration::from_secs(5)).await;
    client.disconnect().await.unwrap();
}

2. 完整客户端实现(订阅+发送)

use nostr_sdk::{Client, Keys, Event, Filter, Kind};
use futures::stream::StreamExt;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 初始化客户端和密钥
    let keys = Keys::generate();
    let client = Client::new();

    // 2. 添加多个中继
    let relays = vec![
        "wss://relay.damus.io",
        "wss://nostr-pub.wellorder.net",
    ];
    
    for relay in relays {
        client.add_relay(relay).await?;
    }
    
    // 3. 连接所有中继
    client.connect().await;

    // 4. 订阅事件
    let filter = Filter::new()
        .kind(Kind::TextNote)
        .limit(10);
        
    let mut notifications = client.notifications();
    client.subscribe(vec![filter]).await;

    // 5. 在单独任务中发送测试事件
    let client_clone = client.clone();
    let keys_clone = keys.clone();
    tokio::spawn(async move {
        let event = Event::new_text_note(&keys_clone, "Hello from Rust SDK!").unwrap();
        tokio::time::sleep(Duration::from_secs(2)).await;
        client_clone.send_event(event).await.unwrap();
    });

    // 6. 处理接收的事件
    while let Some(notification) = notifications.next().await {
        match notification {
            Ok(event) => {
                println!("收到新事件: {}", event.content);
                println!("作者: {}", event.pubkey);
                println!("时间: {}", event.created_at);
            }
            Err(e) => eprintln!("错误: {:?}", e),
        }
    }

    // 7. 断开连接
    client.disconnect().await?;
    Ok(())
}

3. 个人资料管理和加密私信

use nostr_sdk::{Keys, EventBuilder, Kind};
use serde_json::json;

fn main() {
    // 1. 创建密钥对
    let user_keys = Keys::generate();
    let friend_keys = Keys::generate();

    // 2. 更新个人资料
    let profile_event = EventBuilder::new(Kind::Metadata)
        .content(&json!({
            "name": "Rust开发者",
            "about": "nostr-sdk测试账号",
            "picture": "https://example.com/avatar.png"
        }).to_string())
        .to_event(&user_keys)
        .unwrap();
        
    println!("个人资料事件: {:?}", profile_event);

    // 3. 创建加密私信
    let dm_content = "这是一个加密的私密消息";
    let dm_event = EventBuilder::new_encrypted_direct_msg(
        &user_keys,
        &friend_keys.public_key(),
        dm_content,
    ).unwrap()
    .to_event(&user_keys)
    .unwrap();
    
    println!("加密私信: {:?}", dm_event);
}

注意事项

  1. 妥善保管私钥,丢失后无法恢复
  2. 中继服务器可能会限制某些操作
  3. 网络请求是异步的,需要使用async/await
  4. 生产环境应考虑错误处理和重试机制
  5. 建议使用env_logger或类似库添加日志记录
  6. 对于长时间运行的客户端,需要处理重新连接逻辑

nostr-sdk提供了完整的Nostr协议实现,开发者可以基于此构建各种去中心化社交应用。

回到顶部