1
0
hugo/content/blog/2023-02-05-damus.md
2024-04-23 22:21:26 +09:00

185 lines
4.7 KiB
Markdown

+++
date = "2023-02-05"
tags = ["nostr", "rust", "damus","sns"]
title = "damusをはじめてみた"
slug = "damus"
+++
damusはnostr protocolに対応したiosのclientです。
- https://github.com/nostr-protocol/nostr
- https://github.com/damus-io/damus
- https://www.reddit.com/r/nostr/comments/10qmsos/damus_for_ios_is_live/
### verify
https://gist.github.com/metasikander/609a538e6a03b2f67e5c8de625baed3e
public-keyはhexに変換します。
https://damus.io/key/
```sh
# domain root
$ cd public
$ vim ./.well-known/nostr.json
```
```json:/.well-known/nostr.json
{
"names": {
"<name>": "<pubkey>"
}
}
```
### web client
https://snort.social
### cli client
とりあえずcli client作ってpostしてみた。
![](https://raw.githubusercontent.com/syui/img/master/other/nostr_client_rust_20230205_0001.jpg)
exampleとしてはこんな感じになるんじゃないかというのを色々なパターンで書いてみた。
```rust:src/main.rs
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();
}
```
- https://docs.rs/nostr/latest/nostr/
- https://docs.rs/nostr-sdk/latest/nostr_sdk/