main
syui 4 months ago
commit f056ed800a
Signed by: syui
GPG Key ID: 67AC97A939D3EA19

4
.gitignore vendored

@ -0,0 +1,4 @@
config*
*.json
target
*.lock

@ -0,0 +1,26 @@
[package]
name = "nor"
description = "nostr client in rust"
version = "0.0.1"
authors = ["syui <syui@syui.cf>"]
edition = "2021"
[dependencies]
seahorse = "*"
dotenv = "0.15"
serde_derive = "1.0"
serde_json = "1.0"
serde = "*"
config = { git = "https://github.com/mehcode/config-rs", branch = "master" }
shellexpand = "*"
curl = "*"
image = "*"
os_type = "2.4"
toml = "*"
futures = "0.3.5"
url = { version = "2.0", features = ["serde"] }
anyhow = "1"
nostr = "*"
tungstenite = { version = "0.17", features = ["rustls-tls-webpki-roots"]}
nostr-sdk = "*"
tokio = { version = "*", features = ["full"] }

@ -0,0 +1,7 @@
- https://docs.rs/nostr/latest/nostr/
- https://docs.rs/nostr-sdk/latest/nostr_sdk/
```sh
$ cargo build
```

@ -0,0 +1,27 @@
use config::{Config, ConfigError, File};
use serde_derive::Deserialize;
use std::borrow::Cow;
#[derive(Debug, Deserialize)]
#[allow(unused)]
pub struct Data {
pub name: Cow<'static, str>,
pub secret_key: Cow<'static, str>,
pub display_name: Cow<'static, str>,
pub about: Cow<'static, str>,
pub picture: Cow<'static, str>,
pub banner: Cow<'static, str>,
pub nip: Cow<'static, str>,
pub lud: Cow<'static, str>,
}
impl Data {
pub fn new() -> Result<Self, ConfigError> {
let d = shellexpand::tilde("~") + "/.config/nor/config.toml";
let s = Config::builder()
.add_source(File::with_name(&d))
.add_source(config::Environment::with_prefix("APP"))
.build()?;
s.try_deserialize()
}
}

@ -0,0 +1,129 @@
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();
}
Loading…
Cancel
Save