Struct Bot

Source
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>

Source

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?
examples/simple_poll.rs (line 68)
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}
Source

pub fn name(self, name: &str) -> Self

Sets bot’s name.

Examples found in repository?
examples/simple_poll.rs (line 70)
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}
Source

pub fn about(self, about: &str) -> Self

Sets bot’s about info

Examples found in repository?
examples/simple_poll.rs (line 71)
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}
Source

pub fn picture(self, picture_url: &str) -> Self

Set bot’s profile picture

Examples found in repository?
examples/simple_poll.rs (line 72)
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}
Source

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?
examples/simple_poll.rs (line 73)
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}
Source

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.

Source

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?
examples/simple_poll.rs (line 75)
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}
Source

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;
}
Source

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.
Source

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.
Source

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?
examples/simple_poll.rs (line 79)
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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> ErasedDestructor for T
where T: 'static,