Skip to content
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

Bot doesn't connect #28

Closed
jiujitsu opened this issue Apr 27, 2016 · 9 comments
Closed

Bot doesn't connect #28

jiujitsu opened this issue Apr 27, 2016 · 9 comments

Comments

@jiujitsu
Copy link

I'm using Python 3.5.1, and trying to use the example echo.py on a variety of efnet servers. I set ssl to False. I tested on both OSX and Debian. I added some debug statements like this:

@bot.on('CLIENT_CONNECT')
def connect(**kwargs):
    print(kwargs)

    print('in connect sending NICK')
    bot.send('NICK', nick=config.nick)

    print('sending USER')
    bot.send('USER', user=config.nick, realname=config.real_name)
    print('sending JOIN')
    bot.send('JOIN', channel=config.channel)
    print('sent JOIN')

And the output is:

in connect sending NICK
sending USER
sending JOIN
sent JOIN

However, the bot appears to hang at that point. I don't see it join my channel nor do I see it connected to the server at all. Let me know if there is any other info I can provide to help debug. Thanks!

@numberoverzero
Copy link
Owner

numberoverzero commented Apr 27, 2016

What endpoint are you trying to connect to? chat.freenode.net:6697 will fail with Broken Pipe if ssl=False, but chat.freenode.net:6667 will work with ssl=False.

As an aside, you can get more asyncio debugging information by passing an event loop with debug enabled:

import asyncio
loop = asyncio.get_event_loop()
loop.set_debug(True)

bot = bottom.Client(..., loop=loop)

Test script:

import asyncio
import bottom
import logging

logging.basicConfig(level=logging.DEBUG)
config = type("Config", (object,), {})()

config.nick = "bottom-bot"
config.real_name = "bottom-real"
config.channel = "#bottom-dev"

config.host = "chat.freenode.net"
config.port = 6667
config.ssl = False
config.loop = asyncio.get_event_loop()
config.loop.set_debug(True)

bot = bottom.Client(
    host=config.host, port=config.port,
    ssl=config.ssl, loop=config.loop)


@bot.on('CLIENT_CONNECT')
def connect(**kwargs):
    print(kwargs)

    print('in connect sending NICK')
    bot.send('NICK', nick=config.nick)

    print('sending USER')
    bot.send('USER', user=config.nick, realname=config.real_name)
    print('sending JOIN')
    bot.send('JOIN', channel=config.channel)
    print('sent JOIN')


bot.loop.create_task(bot.connect())
bot.loop.run_forever()

This is connecting to 6667 without ssl - to enable ssl, use:

config.ssl = True
config.port = 6697

@jiujitsu
Copy link
Author

Aha! I was using the ssl port on a non ssl server. Once I got past that, I ran into another issue that might be worth documenting. Before sending the join, I had to do await bot.wait('PING'), and change the connect function to be async. This may just be an efnet thing, where it will say you aren't registered if you try to send the join command before responding to the ping. For reference, I the server was: efnet.port80.se.

Anywhoo, I am closing this ticket. Thanks for the help! Showing me how to enable debugging was also very useful.

@thebigmunch
Copy link

I forgot to respond to this issue a while back. The solution of waiting for the server 'PING' is not ideal nor does it reveal the direct cause. The cause is that the examples given send the 'JOIN' command before the server has processed your 'NICK' and 'USER' commands. Also, servers aren't necessarily going to be sending a 'PING' to clients for some time after they connect.

Technically, you should be able to wait for any message from the server starting at 'RPL_WELCOME'.

You might also choose to wait for the end of the message of the day ('RPL_ENDOFMOTD')/no message of the day ('ERR_NOMOTD') or the server to send the user modes message 'MODE'. Waiting for 'MODE' would require support be added for it to bottom.

The examples should probably be changed to include waiting for a server response before sending the 'JOIN' command to demonstrate best practices.

@numberoverzero
Copy link
Owner

numberoverzero commented Oct 8, 2016

This is really good info, thanks @thebigmunch!

I think jiujitsu's comment above is the only mention of waiting for PING, right? I don't see any waiting in echo.py or README.rst.

I'd like to add something to examples/ that demonstrates sending NICK, USER and then waiting for <SOMETHING> before sending JOIN. For a general sample, what would you recommend waiting on? If the usage is tucked away in an example, the README should have some way to discover it. Where would you look in the README if you were searching for this solution?


Your comment also hit on something not covered in the examples: how to wait for one of two signals. This is just using asyncio.wait(..., return_when=FIRST_COMPLETED) but it's not a form people may be used to using, especially just coming to asyncio.

Actually, waiting on first of RPL_ENDOFMOTD, ERR_NOMOTD might be a good way to check off both goals. It could also include how to drop the other Future with `Future.cancel().

@thebigmunch
Copy link

Yes, I the first part of my comment was in regards to jiujitsu's solution; all of the current examples just send 'JOIN' immediately after 'NICK' and 'USER' commands.

Honestly, the README is far too long in my opinion. Much of it should just be left for the docs. Project-related stuff like installation, contributing, etc is great in the README. The single 'Getting Started' section with a simple example is fine, too. And that should probably have a wait added to it. A long, crowded README is more likely to get skipped over/ignored. You can then just link to the examples directory or docs (if adding the examples to the docs).

As for what to wait on, message of the day is definitely a fine choice. I honestly don't know what most clients do, but I think that sounds good.

@numberoverzero
Copy link
Owner

numberoverzero commented Oct 8, 2016

Thanks again for the feedback. Examples now await on MOTD. I've also trimmed the README down and cleaned up the docs a bit. If you don't mind taking a look, I'll add you to the PR.

Edit: @thebigmunch created #33 for the doc changes. Unless you have comments, I'll merge + release tonight or tomorrow.

@meshy
Copy link

meshy commented Oct 9, 2016

There is an interesting parallel between d5425da and gawel/irc3#14.

That issue on irc3 lists waiting for MOTD as a bug because it causes errors when connecting to bouncers. Perhaps it's worth adding a third wait to cover that circumstance? I don't personally use a bouncer, so I'm not exactly sure what to recommend, but PRIVMSG springs to mind. Perhaps there is something more appropriate. I hope that's helpful :)

@meshy
Copy link

meshy commented Oct 9, 2016

Just saw your edit and #33. Would you like me to move my comment to there?

@numberoverzero
Copy link
Owner

Please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants