2023-02-05 / @syui

nostr , rust , damus , sns

damusをはじめてみた

damusはnostr protocolに対応したiosのclientです。

verify

https://gist.github.com/metasikander/609a538e6a03b2f67e5c8de625baed3e

public-keyはhexに変換します。

https://damus.io/key/

# domain root
$ cd public
$ vim ./.well-known/nostr.json
{
  "names": {
    "<name>": "<pubkey>"
  }
}

web client

https://snort.social

cli client

とりあえずcli client作ってpostしてみた。

exampleとしてはこんな感じになるんじゃないかというのを色々なパターンで書いてみた。

pub mod data;
use std::env;
use url::Url;
use data::Data as Datas;
use seahorse::{App, Command, Context};
use nostr::{Event, EventBuilder, Metadata};
use nostr::key::{FromBech32, Keys};
use nostr::message::ClientMessage;
use tungstenite::{connect, Message as WsMessage};
const WS_ENDPOINT: &str = "wss://relay.damus.io";
use nostr_sdk::{Client};
use nostr::SubscriptionFilter;
use nostr::util::time::timestamp;

fn main() {
    let args: Vec<String> = env::args().collect();
    let app = App::new(env!("CARGO_PKG_NAME"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .description(env!("CARGO_PKG_DESCRIPTION"))
        .version(env!("CARGO_PKG_VERSION"))
        .usage("nor [option] [x]")
        .command(
            Command::new("timeline")
            .usage("nor t")
            .description("timeline")
            .alias("t")
            .action(t),
            )
        .command(
            Command::new("notify")
            .usage("nor n")
            .description("notify")
            .alias("n")
            .action(n),
            )
        .command(
            Command::new("status")
            .usage("nor s")
            .description("status")
            .alias("s")
            .action(s),
            )
        .command(
            Command::new("post")
            .usage("nor p {}")
            .description("post message, ex: $ nor p $text")
            .alias("p")
            .action(p),
            ) 
        ;
    app.run(args);
}

#[tokio::main]
async fn timeline() -> anyhow::Result<()> {
    let data = Datas::new().unwrap();
    let my_keys = Keys::from_bech32(&data.secret_key)?;
    let mut client = Client::new(&my_keys);
    client
        .add_relay("wss://relay.damus.io", None)
        .unwrap();
    client.connect_relay("wss://relay.damus.io", true).await.unwrap();
    client.connect().await?;
    let subscription = SubscriptionFilter::new()
        .pubkeys(vec![my_keys.public_key()])
        .since(timestamp());

    let t = client.get_events_of(vec![subscription]).await.unwrap();
    println!("{:#?}", t);
    Ok(())
}

fn t(_c: &Context) {
    timeline().unwrap();
}

#[tokio::main]
async fn notify() -> anyhow::Result<()> {
    let data = Datas::new().unwrap();
    let my_keys = Keys::from_bech32(&data.secret_key)?;
    let client = Client::new(&my_keys);
    let notifications = client.notifications();
    println!("{:?}", notifications);
    Ok(())

    //loop {
    //    let mut notifications = client.notifications();
    //    while let Ok(notification) = notifications.recv().await {
    //        println!("{:?}", notification);
    //    }
    //}
}

fn n(_c: &Context) {
    notify().unwrap();
}

fn status() -> anyhow::Result<()> {
    let data = Datas::new().unwrap();
    let metadata = Metadata::new()
        .name(data.name)
        .display_name(data.display_name)
        .about(data.about)
        .picture(Url::parse(&data.picture)?)
        .nip05(data.nip);
    let my_keys = Keys::from_bech32(&data.secret_key)?;
    let event: Event = EventBuilder::set_metadata(&my_keys, metadata)?.to_event(&my_keys)?;
    println!("{:#?}", event);
    Ok(())
}

fn s(_c: &Context) {
    status().unwrap();
}

fn post(c: &Context) -> anyhow::Result<()> {
    let text = c.args[0].to_string();
    let data = Datas::new().unwrap();
    let my_keys = Keys::from_bech32(&data.secret_key)?;
    let event: Event = EventBuilder::new_text_note(&text, &[]).to_event(&my_keys)?;
    let (mut socket, _response) = connect(WS_ENDPOINT).expect("Can't connect to relay");
    let msg = ClientMessage::new_event(event).to_json();
    socket.write_message(WsMessage::Text(msg))?;
    Ok(())
}

fn p(c: &Context) {
    post(c).unwrap();
}