Closed fmckeogh closed 6 years ago
As it currently stands, you can only have a single message handler per client. That is, for each IrcClient
you have, you can only call IrcClient::stream(...)
once (this is documented there). So, depending on precisely what you meant by "spawning a thread per client message handler," it unfortunately might not be possible. I do have some vague ideas about how we might be able to alleviate this restriction in future versions, but I haven't worked them out yet.
With that out of the way, there should be two ways to implement the tweeter example with the new API. One is a fairly direct port, and the other is relying more heavily on other Rust async libraries. In my personal opinion, the latter is much more pleasant code to read and write.
tweeter.rs
to the new APIextern crate irc;
use std::default::Default;
use std::thread;
use std::time::Duration;
use irc::client::prelude::*;
fn main() {
let config = Config {
nickname: Some("pickles".to_owned()),
server: Some("irc.fyrechat.net".to_owned()),
channels: Some(vec!["#irc-crate".to_owned()]),
..Default::default()
};
// We need to create a reactor first and foremost
let mut reactor = IrcReactor::new().unwrap();
// and then create a client via its API.
let client = reactor.prepare_client_and_connect(&config).unwrap();
// Then, we identify
client.identify().unwrap();
// and clone just as before.
let send_client = client.clone();
// Rather than spawn a thread that reads the messages separately, we register a handler with the
// reactor. just as in the original version, we don't do any real handling and instead just print
// the messages that are received.
reactor.register_client_with_handler(client, |_, message| {
print!("{}", message);
Ok(())
});
// Meanwhile, we need to run the reactor on the thread it was created on (it is not `Send`). So,
// we actually move the sending part (which was previously on the main thread) to the new thread.
thread::spawn(move || {
// But the implementation for sending is entirely the same.
loop {
send_client.send_privmsg("#irc-crate", "TWEET TWEET").unwrap();
thread::sleep(Duration::new(10, 0));
}
});
// Then, on the main thread, we finally run the reactor which blocks the program indefinitely.
reactor.run().unwrap();
}
tokio-timer
and a single threadThe alternative is to actually keep the entire program on one thread and actually run the sending thread as a future on the IrcReactor
. You can do this using tokio-timer
and IrcReactor::register_future(...)
. To do so, we can replace the newly spawned thread with the following code (and an extern crate tokio_timer
):
// We construct an interval using a wheel timer from tokio_timer. This interval will fire
// every 10 seconds (and is accurate to the second).
let send_interval = tokio_timer::wheel()
.tick_duration(Duration::from_secs(1))
.num_slots(256)
.build()
.interval(Duration::from_secs(10));
// And then spawn a new future that performs the given action each time it fires.
reactor.register_future(send_interval.map_err(IrcError::Timer).for_each(move |()| {
// Anything in here will happen every 10 seconds!
send_client.send_privmsg("#irc-crate", "TWEET TWEET")
}));
Thank you so much for your detailed response! :)
I wasn't to clear myself on the multithreaded model, tokio-timer
is definitely a lot cleaner and does exactly what I need. Thanks again! :)
Hello,
I'm really sorry if this is not the right place for this but I'm having a little trouble with the new API.
I'd like to write a program that spawns a thread per client message handler and another thread that sends a message every n seconds, how would I go about doing this?
Thanks :)