pub struct Bot<State: Clone + Send + Sync> { /* private fields */ }
Expand description
Main sctruct that holds every data necessary to run a bot. The core purpose is to take care of the relays connections and listening for commands.
Implementations§
Source§impl<State: Clone + Send + Sync + 'static> Bot<State>
impl<State: Clone + Send + Sync + 'static> Bot<State>
Sourcepub fn new(keypair: KeyPair, relays: Vec<&str>, state: State) -> Self
pub fn new(keypair: KeyPair, relays: Vec<&str>, state: State) -> Self
Basic initialization of the bot.
keypair
Key pair that will be used by the bot to sign messages.relays
List of relays to which the bot will connect to.state
Shared object that will be passed to invoked commands, see Bot::command().
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn name(self, name: &str) -> Self
pub fn name(self, name: &str) -> Self
Sets bot’s name.
name
After connecting to relays this name will be send inside set_metadata kind 0 event, see https://github.com/nostr-protocol/nips/blob/master/01.md#basic-event-kinds.
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn about(self, about: &str) -> Self
pub fn about(self, about: &str) -> Self
Sets bot’s about info
about
After connecting to relays this info will be send inside set_metadata kind 0 event, see https://github.com/nostr-protocol/nips/blob/master/01.md#basic-event-kinds. Also, this is used when generating !help command, see Bot::help().
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn picture(self, picture_url: &str) -> Self
pub fn picture(self, picture_url: &str) -> Self
Set bot’s profile picture
picture_url
After connecting to relays this will be send inside set_metadata kind 0 event, see https://github.com/nostr-protocol/nips/blob/master/01.md#basic-event-kinds.
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn intro_message(self, message: &str) -> Self
pub fn intro_message(self, message: &str) -> Self
Says hello.
message
This message will be send when bot connects to a relay.
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn help(self) -> Self
pub fn help(self) -> Self
Generates “manpage”.
This adds !help command. When invoked it shows info about bot set in Bot::about() and auto-generated list of available commands.
Sourcepub fn command(self, command: Command<State>) -> Self
pub fn command(self, command: Command<State>) -> Self
Registers command
.
When someone replies to a bot, the bot goes through all registered commands and when it finds match it invokes given functor.
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Sourcepub fn spawn(
self,
future: impl Future<Output = ()> + Unpin + Send + 'static,
) -> Self
pub fn spawn( self, future: impl Future<Output = ()> + Unpin + Send + 'static, ) -> Self
Adds a task that will be spawned tokio::spawn.
future
Future is saved and the task is spawned when Bot::run is called and bot connects to the relays.
§Example
// Sending message every 60 seconds
#[tokio::main]
async fn main() {
nostr_bot::init_logger();
let keypair = nostr_bot::keypair_from_secret(
// Your secret goes here
);
let relays = vec![
// List of relays goes here
];
let sender = nostr_bot::new_sender();
// Empty state just for example sake
let state = nostr_bot::wrap_state(());
// Tip: instead of capturing the sender you can capture your state
// and update it here regularly
let alive = {
let sender = sender.clone();
async move {
loop {
let event = nostr_bot::EventNonSigned {
created_at: nostr_bot::unix_timestamp(),
kind: 1,
content: "I'm still alive.".to_string(),
tags: vec![],
}
.sign(&keypair);
sender.lock().await.send(event).await;
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
}
}
};
nostr_bot::Bot::new(keypair, relays, state)
// You have to set the sender here so that the alive future
// and the bot share the same one
.sender(sender)
.spawn(Box::pin(alive))
.run()
.await;
}
Sourcepub fn sender(self, sender: Sender) -> Self
pub fn sender(self, sender: Sender) -> Self
Sets sender.
It can be used together with Bot::spawn to make the bot send messages outside it’s command responses.
sender
Sender that will be used by bot to send nostr messages to relays.
Sourcepub fn use_socks5(self, proxy_addr: &str) -> Self
pub fn use_socks5(self, proxy_addr: &str) -> Self
Tells the bot to use socks5 proxy instead of direct connection to the internet for communication with relays.
If you need anonymity please check yourself there are no leaks.
proxy_addr
Address of the proxy including port, e.g.127.0.0.1:9050
.
Sourcepub async fn run(&mut self)
pub async fn run(&mut self)
Connects to relays, set bot’s profile, send message if set using Bot::intro_message, spawn tasks if given prior by Bot::spawn() and listen to commands.
Examples found in repository?
44async fn main() {
45 init_logger();
46
47 let relays = vec![
48 "wss://nostr-pub.wellorder.net",
49 "wss://relay.damus.io",
50 "wss://relay.nostr.info",
51 ];
52
53 let keypair = keypair_from_secret(
54 // Your secret goes here
55 "0000000000000000000000000000000000000000000000000000000000000001",
56 );
57
58 let question = String::from("Do you think Pluto should be a planet?");
59
60 // Wrap your object into Arc<Mutex> so it can be shared among command handlers
61 let shared_state = wrap_state(Votes {
62 question: question.clone(),
63 yes: 0,
64 no: 0,
65 });
66
67 // And now the Bot
68 Bot::new(keypair, relays, shared_state)
69 // You don't have to set these but then the bot will have incomplete profile info :(
70 .name("poll_bot")
71 .about("Just a bot.")
72 .picture("https://i.imgur.com/ij4XprK.jpeg")
73 .intro_message(&question)
74 // You don't have to specify any command but then what will the bot do? Nothing.
75 .command(Command::new("!yes", wrap!(yes)))
76 .command(Command::new("!no", wrap!(no)))
77 .command(Command::new("!results", wrap!(results)))
78 // And finally run it
79 .run()
80 .await;
81}
Auto Trait Implementations§
impl<State> Freeze for Bot<State>where
State: Freeze,
impl<State> !RefUnwindSafe for Bot<State>
impl<State> Send for Bot<State>
impl<State> !Sync for Bot<State>
impl<State> Unpin for Bot<State>where
State: Unpin,
impl<State> !UnwindSafe for Bot<State>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more