Skip to content

Commit

Permalink
subscription print better, nicer output
Browse files Browse the repository at this point in the history
- it is recommended to put all subscriptions also into the contacts for having nicer aliases
  • Loading branch information
8go committed Dec 8, 2022
1 parent a48cbae commit e6ef452
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "nostr-commander"
version = "0.0.6"
version = "0.0.7"
edition = "2021"
description = "simple but convenient CLI-based Nostr client app for publishing,sending and subscribing"
documentation = "https://docs.rs/nostr-commander"
Expand Down
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ can find the project more easily :heart:.

# What's in the name?

nostr-command*(lin)*er. A word play.
nostr-command(lin)er. A word play.

# Audience, Use cases

Expand Down Expand Up @@ -57,6 +57,63 @@ nostr-command*(lin)*er. A word play.
- Once program is compiled, the executable will be available in target/release/nostr-commander-rs.
- `./target/release/nostr-commander-rs --version # run it and get version`

# Config File

You don't need to know any of this. This is just for the curious ones.

The config file looks something like this. If you want to do some quick testing,
you can copy and paste this config file to get going real fast.

```
{
"secret_key_bech32": "nsec1yljk9us0e3whjnzysu6pqjhnw5wglkr6hvx4vj376fs0sfaxze6qvx5f5x",
"public_key_bech32": "npub1af7ep6s5esrgtc2c7tlvd3v4jpna44qf6nhan8tek6h505nwrvgq38nwz6",
"relays": [
"wss://relay.nostr.info/",
"wss://nostr.ono.re/",
"wss://nostr.rocks/",
"wss://nostr-pub.wellorder.net/",
"wss://nostr.semisol.dev/",
"wss://nostr-relay.wlvs.space/"
],
"metadata": {
"name": "James Jones",
"display_name": "Jim",
"about": "tech nerd and nostr lover"
},
"contacts": [
{
"pk": "887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072",
"relay_url": "wss://nostr.openchain.fr/",
"alias": "HackerNews"
},
{
"pk": "6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964",
"relay_url": "wss://nostr.openchain.fr/",
"alias": "dergigi"
},
{
"pk": "3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c",
"relay_url": "wss://nostr.openchain.fr/",
"alias": "vishalxl"
},
{
"pk": "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245",
"relay_url": "wss://nostr.openchain.fr/",
"alias": "jb55.com"
}
],
"subscribed_authors": [
"6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964",
"3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c"
],
"subscribed_pubkeys": [
"887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072",
"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"
]
}
```

# Example Usage

```
Expand All @@ -65,8 +122,10 @@ $ nostr-commander-rs --create-user --name "James Jones" \
--picture "https://i.imgur.com/mIcObyL.jpeg" \
--nip05 [email protected] \
--add-relay "wss://nostr.openchain.fr" "wss://relay.damus.io" # first time only
$ nostr-commander-rs --add-contact --key "887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072" --alias HackerNews --relay "wss://nostr.openchain.fr/"
$ nostr-commander-rs --publish "Love this protocol"
$ nostr-commander-rs --dm joe "How about pizza tonight?"
$ nostr-commander-rs --subscribe-author npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s
```

# Usage
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.6
0.0.7
144 changes: 122 additions & 22 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,13 @@
//! Please help improve the code and add features :pray: :clap:
//!
//! Usage:
//! - nostr-commander-rs --create-user --name "James Jones" \
//! --display-name Jimmy --about "tech and pizza lover" \
//! --picture "https://i.imgur.com/mIcObyL.jpeg" \
//! --nip05 [email protected] \
//! --add-relay "wss://nostr.openchain.fr" "wss://relay.damus.io" # first time only
//! - nostr-commander-rs --publish "Love this protocol"
//! - nostr-commander-rs --dm [email protected] "How about pizza tonight?"
//!
//! For more information, see the README.md
//! - run `nostr-commander-rs --help`
//!
//! For more information, see read the README.md
//! <https://github.com/8go/nostr-commander-rs/blob/main/README.md>
//! file.
// #![allow(dead_code)] // crate-level allow // Todo
#![allow(dead_code)] // crate-level allow // Todo
#![allow(unused_variables)] // Todo
#![allow(unused_imports)] // Todo

Expand All @@ -43,7 +37,10 @@ use update_informer::{registry, Check};
use url::Url;

use nostr_sdk::{
nostr::contact::Contact,
nostr::event::kind::Kind,
nostr::event::kind::KindBase,
nostr::contact::Contact,
nostr::event::tag::TagKind,
nostr::key::XOnlyPublicKey,
nostr::key::{FromBech32, KeyError, Keys, ToBech32},
nostr::message::relay::RelayMessage,
Expand Down Expand Up @@ -1396,12 +1393,69 @@ pub(crate) async fn cli_dm(client: &Client, ap: &mut Args) -> Result<(), Error>
}
}

/// Is key in subscribed_authors list?
pub(crate) fn is_subscribed_author(ap: &Args, pkey: &XOnlyPublicKey) -> bool {
ap.creds.subscribed_authors.contains(pkey)
}

/// Get contact for given alias.
/// Returns None if alias does not exist in contact list.
pub(crate) fn get_contact(ap: &Args, alias: &str) -> Option<Contact> {
pub(crate) fn get_contact_by_alias(ap: &Args, alias: &str) -> Option<Contact> {
ap.creds.contacts.iter().find(|s| s.alias == alias).cloned()
}

/// Get contact for given pubkey.
/// Returns None if pubkey does not exist in contact list.
pub(crate) fn get_contact_by_key(ap: &Args, pkey: XOnlyPublicKey) -> Option<Contact> {
ap.creds.contacts.iter().find(|s| s.pk == pkey).cloned()
}

/// Get contact alias for given pubkey, or if not in contacts return given pubkey.
/// Returns alias if contact with this pubkey exists.
/// Returns input pubkey if no contact with this pubkey exists.
pub(crate) fn get_contact_alias_or_keystr_by_key(ap: &Args, pkey: XOnlyPublicKey) -> String {
match get_contact_by_key(ap, pkey) {
Some(c) => c.alias,
None => pkey.to_string(),
}
}

/// Get contact alias for given pubkey, or if not in contacts return None.
/// Returns Some(alias) if contact with this pubkey exists.
/// Returns None if no contact with this pubkey exists.
pub(crate) fn get_contact_alias_by_key(ap: &Args, pkey: XOnlyPublicKey) -> Option<String> {
match get_contact_by_key(ap, pkey) {
Some(c) => Some(c.alias),
None => None,
}
}

/// Get contact alias for given pubkey string (string of XOnlyPublicKey), or if not in contacts return given pubkey.
/// Returns alias if contact with this pubkey exists.
/// Returns input pubkey if no contact with this pubkey exists.
pub(crate) fn get_contact_alias_or_keystr_by_keystr(ap: &Args, pkeystr: &str) -> String {
match XOnlyPublicKey::from_str(pkeystr) {
Ok(pkey) => match get_contact_by_key(ap, pkey) {
Some(c) => c.alias,
None => pkey.to_string(),
},
Err(_) => pkeystr.to_string(),
}
}

/// Get contact alias for given pubkey string (string of XOnlyPublicKey), or if not in contacts return None.
/// Returns Some(alias) if contact with this pubkey exists.
/// Returns None if no contact with this pubkey exists.
pub(crate) fn get_contact_alias_by_keystr(ap: &Args, pkeystr: &str) -> Option<String> {
match XOnlyPublicKey::from_str(pkeystr) {
Ok(pkey) => match get_contact_by_key(ap, pkey) {
Some(c) => Some(c.alias),
None => None,
},
Err(_) => None,
}
}

/// Handle the --add-conect CLI argument, write contacts from CLI args into creds data structure
pub(crate) async fn cli_add_contact(client: &Client, ap: &mut Args) -> Result<(), Error> {
let mut err_count = 0usize;
Expand All @@ -1423,7 +1477,7 @@ pub(crate) async fn cli_add_contact(client: &Client, ap: &mut Args) -> Result<()
i += 1;
continue;
}
if get_contact(ap, ap.alias[i].trim()).is_some() {
if get_contact_by_alias(ap, ap.alias[i].trim()).is_some() {
error!("Invalid user alias. Alias already exists. Alias must be unique. Skipping this contact.");
err_count += 1;
i += 1;
Expand Down Expand Up @@ -1513,7 +1567,7 @@ pub(crate) async fn cli_subscribe_author(client: &mut Client, ap: &mut Args) ->
/// Convert npub1... Bech32 key or Hex key or contact alias into a XOnlyPublicKey
/// Returns Error if neither valid Bech32, nor Hex key, nor contact alias.
pub(crate) fn cstr_to_pubkey(ap: &Args, s: &str) -> Result<XOnlyPublicKey, Error> {
match get_contact(ap, s) {
match get_contact_by_alias(ap, s) {
Some(c) => Ok(c.pk),
None => str_to_pubkey(s),
}
Expand Down Expand Up @@ -1937,24 +1991,70 @@ async fn main() -> Result<(), Error> {
// Handle notifications
match client
.handle_notifications(|notification| {
debug!("Notification: {:?}", notification);
// debug!("Notification: {:?}", notification);
match notification {
ReceivedEvent(ev) => {
debug!("Event: {:?}", ev);
debug!("Event-Event: content {:?}, kind {:?}", ev.content, ev.kind);
}
ReceivedMessage(msg) => {
debug!("Message: {:?}", msg);
// Notification: ReceivedMessage(Ok { event_id: 123, status: true, message: "" })
// confirmation of notice having been relayed
// debug!("Message: {:?}", msg);
match msg {
RelayMessage::Ok {event_id, status, message } => {
println!("OK: Notice or DM was relayed. Event id is {:?}. Status is {:?} and message is {:?}. You can investigate this event by looking it up on https://nostr.com/e/{}", event_id, status, message, event_id.to_string());
// Notification: ReceivedMessage(Ok { event_id: 123, status: true, message: "" })
// confirmation of notice having been relayed
info!("Message-OK: Notice or DM was relayed. Event id is {:?}. Status is {:?} and message is {:?}. You can investigate this event by looking it up on https://nostr.com/e/{}", event_id, status, message, event_id.to_string());
println!("Message-OK: Notice or DM was relayed. Event id is {:?}. Status is {:?} and message is {:?}. You can investigate this event by looking it up on https://nostr.com/e/{}", event_id, status, message, event_id.to_string());
},
RelayMessage::Notice { message } => {
debug!("Notice: {:?}", message);
debug!("Message-Notice: {:?}", message);
}
RelayMessage::Event {event, subscription_id}=> {
// kind: Base(ChannelMessage) and Base(TextNote) and Base(Reaction)
let mut tags = "".to_owned();
let mut first = true;
for t in &event.tags {
match t.kind() {
Ok(TagKind::P) => {
match t.content() {
Some(c) => {
debug!("tag: {:?}", get_contact_alias_or_keystr_by_keystr(&ap, c));
match get_contact_alias_by_keystr(&ap, c) {
Some(a) => {
if !first { tags += ", "; };
tags += &a;
first = false;
},
_ => ()
}
}
None => ()
}
},
Ok(TagKind::E) => (),
Ok(TagKind::Nonce) => (),
Err(_) => ()
}
}
info!("Message-Event: content {:?}, kind {:?}, from pubkey {:?}, with tags {:?}", event.content, event.kind, get_contact_alias_or_keystr_by_key(&ap, event.pubkey), event.tags);
let mut key_author = "key";
if is_subscribed_author(&ap, &event.pubkey) {
key_author = "author";
tags = get_contact_alias_or_keystr_by_key(&ap, event.pubkey);
};
match event.kind {
Kind::Base(KindBase::ContactList) => (),
Kind::Base(KindBase::Reaction) => (),
Kind::Base(KindBase::TextNote) => {
println!("Subscription by {} ({}): content {:?}, kind {:?}, from pubkey {:?}", key_author, tags, event.content, event.kind, get_contact_alias_or_keystr_by_key(&ap, event.pubkey));
},
Kind::Base(KindBase::ChannelMessage) => {
println!("Subscription by {} ({}): content {:?}, kind {:?}, from pubkey {:?}", key_author, tags, event.content, event.kind, get_contact_alias_or_keystr_by_key(&ap, event.pubkey));
},
_ => ()
}
},
RelayMessage::Empty => (),
_ => (),
RelayMessage::EndOfStoredEvents {subscription_id} => (),
}
}
}
Expand Down

0 comments on commit e6ef452

Please sign in to comment.