Help with creating an IRC bot


#1

I am looking at converting an IRC bot I have written in Python into Rust (primarily for performance reasons). I would appreciate advice on the best framework(s) to use.

The bot monitors both a set of IRC channels for requests, as well as a log stream being delivered from a socket, so the bot has to be fully asynchronous. The IRC communication is also done over TLS, which seems to complicate matters.

I have no problem with text parsing, either for the log stream or IRC requests, though I don’t really have time to implement an IRC protocol library on my own. I’ve looked into Tokio but all the examples I’ve seen are either for use as a client or as a server exclusively, and this seems to be both (or at least a client of two completely separate things at once). I have developed another trivial program using mio so I’m familiar with that as well.

Any suggestions where I should start?


#2

For TLS, I would check out the native-tls crate.

extern crate native_tls;

use native_tls::TlsConnector;
use std::io::{Read, Write};
use std::net::TcpStream;

fn main() {
    let connector = TlsConnector::builder().unwrap().build().unwrap();

    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = connector.connect("google.com", stream).unwrap();

    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut res = vec![];
    stream.read_to_end(&mut res).unwrap();
    println!("{}", String::from_utf8_lossy(&res));
}

#3

If you’re willing to try with Tokio, this IRC library seems very promising from my cursory inspection of its API. It supports TLS, so you shouldn’t have to worry about that.

One way of structuring the bot would be to create your own event loop, a custom struct which will contain all IRC connections (obtained with IrcClient::new_future() from the linked crate, resolved to the appropriate handle from which the corresponding message Stream has been extracted, and the sending future spawned on the event loop) and the connection to the log stream, then implement Future for that struct, placing the message handling and dispatching logic in its poll() function.

Complications like timeouts and reconnections, if needed, can probably be added later.