aatxe / irc

the irc crate – usable, async IRC for Rust
Mozilla Public License 2.0
530 stars 97 forks source link

Connecting takes very long, does future not return? #112

Closed ghost closed 6 years ago

ghost commented 6 years ago

First off: Thanks for this library. I was about to start my own, then I found this one and am eager to get it running for me.

Now to my problem:

extern crate irc;

use std::default::Default;
use irc::client::prelude::*;

fn main() {

    // FIXME, find out why it can not find the config.toml at all
   /* let config = Config::load("config.toml").unwrap();
    let client = IrcClient::from_config(config).unwrap();*/

    let config = Config {
        nickname: Some(format!("testbot")),
        //username: Some("testobot".to_owned()),
        server: Some(format!("irc.freenode.net")),
        //port: Some(6697),
        use_ssl: Some(true),
        channels: Some(vec![format!("#testbot12")]),
        ..Default::default()
    };

    let client = IrcClient::from_config(config).unwrap();

    client.identify().unwrap();
    match client.send_join("#testbot12") {
        Ok(s) => println!("Yeah!"),
        Err(e) => panic!("Boooh"),
    }
    client.for_each_incoming(|message| {

        println!("message: {}", message);

        if let Command::NOTICE(ref channel, ref message) = message.command {
            println!("Got new notice: {:?}", message)
        }

        /*if let Command::PING(ref channel, ref message) = message.command {
            println!("Received ping! {:?}", message);
            client.send_pong("I am alive!");
        }*/

        if let Command::PRIVMSG(ref channel, ref message) = message.command {
            println!("priv message: {}", message);
            if message.contains(client.current_nickname()) {
                client.send_privmsg(channel, "I heard you :)").unwrap();
            }
        }

    }).unwrap()
}

Very straight forward code, I guess.

cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running target/debug/testbot Yeah!

My problem is, that the bot immediately prints "Yeah!" which means it connected to the channel. But it does NOT. It takes 2-5 minutes, sometimes even not then, until it shows up. I get nothing else in the logs. I tried the same on an irc server of a friend of mine. There is nothing special going on, according to the logs, but the bot simply does not connect there at all.

A similar Scala bot I wrote from scratch connects just fine.

Now I really wonder, what can be the cause of this? At first I thought some SSL problem, but the same happens without SSL and the Scala bot works just fine (without any special cert setup)

Another thing is, that the bot does not connect if I don't add a send_join after the identify()-call. I checked the impl, but couldn't find where it's supposed to join any channel.

``identify() looks just like that:


    where
        Self: Sized,
    {
        // Send a CAP END to signify that we're IRCv3-compliant (and to end negotiations!).
        self.send(CAP(None, END, None, None))?;
        if self.config().password() != "" {
            self.send(PASS(self.config().password().to_owned()))?;
        }
        self.send(NICK(self.config().nickname()?.to_owned()))?;
        self.send(USER(
            self.config().username().to_owned(),
            "0".to_owned(),
            self.config().real_name().to_owned(),
        ))?;
        Ok(())
    }```

I get the feeling I am missing something big here.
Can you shed some light, please? (Or at least tell me to fuck off, because the error is somewhere withing my setup)
aatxe commented 6 years ago

The problem is essentially that you're sending the JOIN too quickly. After sending an identify, the server will process it and send a response with a bunch of info. To my knowledge, most servers will not accept a JOIN until they finish sending the MOTD. So, you'd want to wait until receiving either RPL_ENDOFMOTD or ERR_NOMOTD before sending JOIN.

Fortunately, this particular pattern is already captured and you can specify in your Config a list of channels to join. This will wait in the fashion I described above. However, given that JOIN is far from the only functionality that won't work before the MOTD has been received, it would probably be useful to be able to do something along the lines of client.await_motd() which would block the thread appropriately.

ghost commented 6 years ago

Thanks for the response. As you can see I did configure the channels in the config, but that was never enough for the bot to join any of them (as described)

aatxe commented 6 years ago

Ah, sorry about that. I missed the line in the Config somehow (probably because I was focused on the send_join part). This is actually a regression in a7ae091ff5ec758e0d976b3969701f72b712406e that went unnoticed because it was on a branch that I wasn't doing most of my testing on, but still got merged in. Sorry about that. I've yanked the broken version, and am in the process of uploading a new release.

aatxe commented 6 years ago

The new release has been published. Sorry again about the regression.

ghost commented 6 years ago

Thanks a lot! Now EVERYTHING works like a charm for me. It connects immediately to all the channels specified and the business-logic can now be implemented.