-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Re-]Implement Automatic Reconnection #88
Comments
Just to clarify: is current implementation is not able to reconnect or is it lacking something? |
Prior to 0.12.0, there was a broken implementation. As of 0.12.0, there is no automatic reconnection whatsoever. It should be possible for a library consumer to implement it themselves though in a fairly straightforward way. If you have set up your own event loop with From my perspective, the perfect automatic reconnection implementation for this library would restore all possible channel membership (using the chanlists feature). It also wouldn't require the exposure of tokio internals as above. Reconnecting to just what's specified in the config might be a nice stepping stone though. It's been suggested to me a few times that this could all be done inside the transport (i.e. src/client/transport.rs), but I have not yet grokked how to do it. |
I'm planning on using your library to implement IRC bot so I wanted to have clarifications. |
To anyone looking here, this is less of an issue today than in the past (perhaps to the point where we don't need it in the library, but I'm not committing one way or the other yet). As of extern crate irc;
use irc::client::prelude::*;
fn main() {
// We can also load the Config at runtime via Config::load("path/to/config.toml")
let config = Config {
nickname: Some("the-irc-crate".to_owned()),
server: Some("irc.pdgn.co".to_owned()),
channels: Some(vec!["#test".to_owned()]),
..Config::default()
};
while let Err(e) = implementation(&config) {
eprintln!("{}", e);
// One might wish to add a backoff strategy here to prevent reconnection attempts in a tight loop.
}
}
fn implementation(config: &Config) -> irc::error::Result<()> {
let mut reactor = IrcReactor::new()?;
let client = reactor.prepare_client_and_connect(config)?;
client.identify()?;
reactor.register_client_with_handler(client, |client, message| {
print!("{}", message);
// And here we can do whatever we want with the messages.
Ok(())
});
reactor.run()
} |
As of static mut irc_client: Option<Box<Client>> = None;
#[tokio::main]
async fn main() -> Result<(), failure::Error> {
...
let (tx, irc_stream) = mpsc::unbounded_channel();
let irc_tasklet = {
let irc_client_h = unsafe { &mut irc_client };
tokio::task::spawn(async move {
loop {
// Sleep-loop until creating an IRC client succeeds. I think it's async, so I have
// no idea how it can fail. But go ahead and gracefully retry.
let mut new_client = {
let mut r;
loop {
r = create_irc(&irc_user, &irc_nickserv_pass).await;
if r.is_ok() {
break;
}
log::error!("Failed to create irc client, sleeping 60 seconds: {}", r.unwrap_err());
tokio::time::delay_for(std::time::Duration::from_secs(60)).await;
}
r.unwrap()
};
*irc_client_h = Some(new_client);
let irc_stream = irc_client_h.as_mut().unwrap().as_mut().stream().unwrap();
// Fuse IRC stream /after/ first fatal error.
let mut conn_error = false;
let irc_stream = irc_stream.take_while(move |x| {
if conn_error {
return futures::future::ready(false);
}
if x.is_err() {
conn_err = match x.as_ref().unwrap_err() {
irc::error::Error::PingTimeout => true,
irc::error::Error::Io(_) => true,
irc::error::Error::Tls(_) => true,
_ => false
};
}
return futures::future::ready(true);
});
// Shovel IRC events from the current client's stream into our queue, until a fatal
// error was detected.
irc_stream.for_each(|e| {
tx.send(e).unwrap();
futures::future::ready(())
}).await;
log::error!("IRC fatal error, trying to reconnect.");
*irc_client_h = None;
// Implicit drop of irc_stream, irc_client.
}
})
};
...
unsafe {
if irc_client.is_some() {
irc_client.as_ref().unwrap().send_quit("quitting")?;
}
}
...
irc_tasklet.await?;
... |
Automatic reconnection is clearly a desirable feature, and implementing it correctly should be a lot easier with the new tokio backend in 0.12.0.
The text was updated successfully, but these errors were encountered: