Code Monkey home page Code Monkey logo

irc3's Introduction

irc3. pluggable irc client library based on python's asyncio

image

image

A pluggable irc client library based on python's asyncio.

Ceative Commons – Attribution (CC BY 3.0) - Hydra designed by Huu Nguyen from the Noun Project - http://thenounproject.com/term/hydra/46963/

Requires python 3.5+

Python 2 is no longer supported, but if you don't have a choice you can use an older version:

$ pip install "irc3<0.9"

Source: https://github.com/gawel/irc3/

Docs: https://irc3.readthedocs.io/

Irc: irc://irc.freenode.net/irc3 (www)

I've spent hours writing this software, with love. Please consider tipping if you like it:

BTC: 1PruQAwByDndFZ7vTeJhyWefAghaZx9RZg

ETH: 0xb6418036d8E06c60C4D91c17d72Df6e1e5b15CE6

LTC: LY6CdZcDbxnBX9GFBJ45TqVj8NykBBqsmT

irc3's People

Contributors

adevore avatar adongy avatar amorporkian avatar bacher09 avatar belak avatar chassing avatar danieloaks avatar gawel avatar gtmanfred avatar harmon758 avatar jpcw avatar jpneverwas avatar jtdroste avatar julienpalard avatar mattbox avatar meshy avatar mickael9 avatar nitori avatar pypingou avatar ryanmaclean avatar saimn avatar singingwolfboy avatar thereverend403 avatar thomwiggers avatar thor77 avatar tnt4brain avatar valhallasw avatar wooble avatar yuvallanger avatar zopieux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

irc3's Issues

Asyncio blocking

Hi,

i'm trying to use the bot in order to provide an irc logger. Basicly this (heriting from RainbowLoggingHandler for coloration of the log)

# pour un logging efficace
import logging
import logging.handlers
from rainbow_logging_handler import RainbowLoggingHandler

# pour une gestion plus jolie des path
from path import path

# to log to irc3
import irc3


class IrcHandler(RainbowLoggingHandler):
    def __init__(self, nick, host, channels: list, port=6667, ssl=False, **kwargs):
        super().__init__(None, kwargs)
        self.channels = channels
        self.bot = irc3.IrcBot(nick=nick, autojoins=channels, host=host, port=port, ssl=ssl,
                               includes=['irc3.plugins.core'])

        self.bot.run()

    def format(self, record):
        message = self.colorize(record)
        return message

    def emit(self, record):
        try:
            msg = self.format(record)
            msg = self._encode(msg)
            for chan in self.channels:
                self.bot.privmsg(chan, msg)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.handleError(record)

Basicly bot.run() is blocking the process. T know it's a feature not a bug. I look into stack overflow, and find run asyncio main loop in thread (bahh) and use executor. I tried both and can't get one working. Moreover I'm not sure asyncio call are thread safe.

Normally I dont request help but if you find some time to give me advice, I would make a plugin with it and push it.

Importing tinydb in a plugin makes the plugin unable to be loaded

Given the following plugin:

# ./someplugin.py
import irc3
from irc3.plugins.command import command
from tinydb import TinyDB

@irc3.plugin
class SomePlugin(object):
    def __init__(self, bot):
        self.bot = bot

And following configuration file:

# ./config.ini
[bot]
nick = ABot
realname = Robo

host = irc.rizon.net
port = 6697
ssl = true
ssl_verify = CERT_NONE

includes =
    irc3.plugins.command
    someplugin

And invoking the bot as:

irc3 config.ini

An error is generated:

File "C:\Python27\lib\site-packages\irc3\utils.py", line 314, in maybedotted
    'Not able to resolve %s' % name)
LookupError: Not able to resolve someplugin

Deleting the from tinydb import TinyDB line from the plugin results in normal behavior.

  • Python 2.7.10 on Windows
  • irc3 0.8.5
  • tinydb 3.0.0

Validate irc nick

Does/could irc3 provide a way to validate if a certain irc nick exists on a server?

README.rst has UTF-8 characters which trips over setup.py

I get the following exception on FreeBSD:

  File "<string>", line 17, in <module>

  File "/tmp/pip_build_root/irc3/setup.py", line 40, in <module>

    long_description=read('README.rst'),

  File "/tmp/pip_build_root/irc3/setup.py", line 33, in read

    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()

  File "/root/.pyenv/versions/3.4.0/lib/python3.4/encodings/ascii.py", line 26, in decode

    return codecs.ascii_decode(input, self.errors)[0]

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 734: ordinal not in range(128)

This is because the open call in the read method in setup.py is not set to read UTF-8 characters (which README.rst apparently has).

A solution would be either to make README.rst all ASCII, or to change the open() call to include the UTF-8 encoding.

Ability to reload plugins on the fly

It would be usefull when developing a plugin to be able to reload a specific plugin or all the plugins on the fly. I'm not sure where that new function should be available, maybe in the IrcBot instance or in a new plugin. A way to detect the reload of a plugin must also be provided, maybe a simple "before_reload" or "on_unload" method on the plugin's instance should be called.

Some servers don't like a lot of reconnection in a short period of time and this also would be usefull to make littles changes in a plugin while keeping the entire bot available for the users in the channel.

vhosts?

does this library support vhosts or binding to a certain address?

Trying to send too large messages may result in RevQ exceeded

Due to circumstances my bot today rendered too large responses, which led to it getting killed for RevQ exceeded. It'd probably be better if irc3 would drop those messages or snip them, probably while printing a warning or something like that.

Why fix this in irc3 and not in the offending plugin? It seems like this would be an issue that could potentially and unexpectedly affect a lot of different plugins, for example if you're consuming an API which suddenly returns unexpectedly large results.

Exceptions on clean shutdown

As we briefly discussed on IRC, passing SIGINT or calling self.bot.SIGINT() exits irc3 uncleanly.

ERROR asyncio Task was destroyed but it is pending!
task: >Task pending coro=>process_queue() running at /home/brotherBox/venv/lib/python3.4/site-packages/irc3-0.9.3.dev0-py3.4.egg/irc3/init.py:209> wait_for=>Future finished result=None>>
Exception ignored in: >bound method _UnixSelectorEventLoop.del of >_UnixSelectorEventLoop running=False closed=True debug=False>>
Traceback (most recent call last):
File "/home/brotherBox/venv/lib/python3.4/site-packages/asyncio-3.4.4-py3.4.egg/asyncio/base_events.py", line 431, in del
File "/home/brotherBox/venv/lib/python3.4/site-packages/asyncio-3.4.4-py3.4.egg/asyncio/unix_events.py", line 58, in close
File "/home/brotherBox/venv/lib/python3.4/site-packages/asyncio-3.4.4-py3.4.egg/asyncio/unix_events.py", line 139, in remove_signal_handler
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object

I run irc3 in a virtual env, running with the following packages:

asyncio==3.4.4
beautifulsoup4==4.4.1
docopt==0.6.2
irc3==0.9.3.dev0
requests==2.10.0
venusian==1.0

I run Python 3.4 on Ubuntu 14.04.

Thank you for your consideration.

Prevent flood by the bot

Currently if we have a plugin that returns a lot of data, irc3 will return it all potentially leading to flood in the channel.

It would be nice to have a plugin to restrict the output returned by irc3.

supybot for example will return the first part of the result and the next parts only if the user asks for .more.

Rejoin channels

Hi,

It's a great module and saved me a lot of time but there is some problems with rejoining password protected channels. The bot successfully joins the channel at startup, the problem lies in the plugin autojoins.py when it tries to rejoin. I looked in the code and it doesn't try joining the channel by using the strings it gets from the config file, where I put the channels in the format " " so the bot can't join the password protected channel after kick or loss of connection.

I made a workaround so my bot could rejoin by using a for-statement that iterates over an if-statement testing the return code from the startswith-method by iterating over self.channels in the event on_kick and on_err_join to rejoin by using the string gotten from the config. A more permanent fix can be made, I have one solution that can be of intrest.

It would be great if the bot could rejoin password protected channels too.

Best regards, No-0n3

Logger events trigger twice

I have a logger bot running on Heroku using my s3_handler branch. The repository that is actually running on Heroku is here: https://github.com/singingwolfboy/edxbot However, events are being triggered twice. Here's an example of a log file that the bot generated:

09:48 edxbottest joined #edx-code-test
09:48 edxbottest joined #edx-code-test
20:49 singingwolfboy joined #edx-code-test
20:49 edxbottest joined #edx-code-test
20:49 <singingwolfboy> t-t-t-test
20:49 <edxbottest> t-t-t-test

You can see that each event is duplicated, once with the nick of the person who actually fired the event, and once with the nick of the bot. Any idea what's going on here, or how to fix it? My pull request doesn't modify any of the event-handling code at all, and I don't think there's anything special about running it on Heroku, either.

bin/ folder is missing

Stuff like the Makefile depend on scripts in a folder called bin/. However, this folder is not part of the repository. Could it be added?

IRC Bot for python 3

I am the author of an existing IRC Bot project which is for python 2.7 and currently lacks a complete strategy for moving to python 3. The project is at https://github.com/kiwiheretic/logos-v2 and has a wiki at https://github.com/kiwiheretic/logos-v2/wiki. I am looking at your project as a possible migration option as it would be easier for me to just concentrate on plugins rather than have to maintain an entire bot. Also I wish to avoid reinventing wheels that I don't have to when I eventually move to python 3. (Especially seeing that Twisted seems unsupported on Python 3). However there are some things about your project I am not clear about and hopefully you will be able to answer them for me.

  • I see you have some kind of permissions (which you appear to call guards) that restrict certain commands to certain users. How does this work in practice and what kind of authentication mechanism do you use? (ie Nickserv, logging into bot, etc)
  • Can your bot operate in more than one room with different plugins active for certain rooms and not in others?
  • Is there any mechanism for one plugin to pass data to another plugin? (Yeah, I know this sounds strange but I am thinking in terms of some kind of message broadcasting system where each plugin can opt to listen or not listen. I have one plugin that listens to data from one plugin and uses a wordpress plugin to log the data.)
  • How do you deal with the blocking problem when interacting with web services like twitter etc?

Thanking you, in advance, for your time.

Other user levels (&, ~)

On a lot of IRC networks there are more user modes than just +v (+), +h (%) and +o (@). Inspircd for instance also supports +a(&) and +q(~) for channel admin (can access CS) and channel owner. irc3.plugins.userlist currently doesn't seem to support those modes.

I don't know what the scope is of this project, IRC servers differ a lot on tiny details like this. You may or may not want do deal with these issues, but then you maybe should put this into the documentation.

Better nickname detection

When using the shell_command plugin, the plugin will react as soon as a simple substring match of its nickname is found. Could you verify that the nickname has at least boundaries around it when it matches, eg /\b$nick\b/ ?

Call /me command

Hi,
Is irc3 able to send /me commands ?

If I do a "/me say hello", and send it with bot.privmsg, the result in an irc client, is a message from the bot like "/me say hello" rather than "* bot say hello"

It looks like the library is escaping the content sent. Is there a way to call the /me command by another way ?

Thanks,
Audric

License

It'd be great if you could add a license to this repository. There's some code I'd like to fork to use in another project, but without a license I'm unable to do so.

Problems accessing IRC topic

So I'm currently trying to retrieve and set the topic of a channel but I cannot get my code to work. I've tried requesting the topic with bot.topic(chan) in a cron and then receiving the event with the event decorator and the rfc.RPL_TOPIC but that yielded no results at all.

Is there something I'm missing? I'd happily PR an example after I got a working version for this so others don't run into the same problem.

Problem importing a pyvenv installed irc3 into a global ipython3

irc3 is installed in the benny pyvenv, while ipython3 was installed to the yuvallanger user environment using python3 -m pip install --user ipython.

The error:

(benny) yuvallanger@yankel-Lenovo-G505:~/projects/benny⟫ ipython3
import irc3
/home/yuvallanger/.local/lib/python3.5/site-packages/IPython/core/interactiveshell.py:712: UserWarning: Attempting to work in a virtua
lenv. If you encounter problems, please install IPython inside the virtualenv.
  warn("Attempting to work in a virtualenv. If you encounter problems, please "
Python 3.5.2 (default, Jul  5 2016, 12:43:10)
Type "copyright", "credits" or "license" for more information.

IPython 5.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import irc3
---------------------------------------------------------------------------
DistributionNotFound                      Traceback (most recent call last)
<ipython-input-1-457396cbab9d> in <module>()
----> 1 import irc3

/home/yuvallanger/.virtualenvs/benny/lib/python3.5/site-packages/irc3/__init__.py in <module>()
     12 from . import utils
     13 from . import rfc
---> 14 from . import base
     15 from irc3.compat import urlopen
     16 from .compat import text_type

/home/yuvallanger/.virtualenvs/benny/lib/python3.5/site-packages/irc3/base.py in <module>()
     19     version = ''
     20 else:
---> 21     version = pkg_resources.get_distribution('irc3').version
     22
     23

/home/yuvallanger/.local/lib/python3.5/site-packages/pkg_resources/__init__.py in get_distribution(dist)
    533         dist = Requirement.parse(dist)
    534     if isinstance(dist, Requirement):
--> 535         dist = get_provider(dist)
    536     if not isinstance(dist, Distribution):
    537         raise TypeError("Expected string, Requirement, or Distribution", dist)

/home/yuvallanger/.local/lib/python3.5/site-packages/pkg_resources/__init__.py in get_provider(moduleOrReq)
    413     """Return an IResourceProvider for the named module or requirement"""
    414     if isinstance(moduleOrReq, Requirement):
--> 415         return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
    416     try:
    417         module = sys.modules[moduleOrReq]

/home/yuvallanger/.local/lib/python3.5/site-packages/pkg_resources/__init__.py in require(self, *requirements)
    941         included, even if they were already activated in this working set.
    942         """
--> 943         needed = self.resolve(parse_requirements(requirements))
    944
    945         for dist in needed:

/home/yuvallanger/.local/lib/python3.5/site-packages/pkg_resources/__init__.py in resolve(self, requirements, env, installer, replace_
conflicting)
    827                     if dist is None:
    828                         requirers = required_by.get(req, None)
--> 829                         raise DistributionNotFound(req, requirers)
    830                 to_activate.append(dist)
    831             if dist not in req:

DistributionNotFound: The 'irc3' distribution was not found and is required by the application

In [2]:

ping pong

Just started using IRC3 and having an issue where the program keeps thinking it is disconnected (freenode if it matters):

INFO irc3.totallynotabot We're waiting a ping for too long. Trying to reconnect...
CRITICAL irc3.totallynotabot connection lost (4350070008): 'No pong reply'

However it is not disconnected. This causes it to attempt to reconnect and then ends up making a another connection with a different username.

commands plugin : "AssertionError: yield from wasn't used with future" when using loop.run_in_executor

Hi, I've encountered what seems to be a bug when using the commands plugin.

Here's the fairly simple plugin.

import irc3
from irc3.plugins.command import command
import pipeau

@irc3.plugin
class Plugin:
    def __init__(self, bot):
        self.bot = bot

    @command(permission='view')
    def eddy_malou(self, mask, target, args):
        """Quotes from http://eddy-malou.com.

            %%eddy_malou
        """
        msg = yield from pipeau.eddy_malou()
        yield msg

And here's the pipeau.eddy_malou() function :

@asyncio.coroutine
def load_page_source_async(url):
    loop = asyncio.get_event_loop()
    page_source = yield from loop.run_in_executor(None, load_page_source, url) # error seems to come from here
    return page_source

@asyncio.coroutine
def eddy_malou():
    """Coroutine loading a quote from http://www.pipotronic.com."""
    page_source = yield from load_page_source_async('http://eddy-malou.com')
    soup = BeautifulSoup(page_source)
    base_element = soup.find('p', { 'id': 'maloutot' })
    return element_contents(base_element)

I end up with the following message :

ERROR asyncio    Exception in callback <bound method event.async_callback of <bound event :(?P<mask>\S+) PRIVMSG (?P<target>\S+) :{re_cmd}(?P<cmd>\w+)(\s(?P<data>\S.*)|$) to <bound method Commands.on_command of <Commands ['!eddy_malou', '!help', '!ping', '!pipotronic']>>>>({'mask': '[email protected]', 'target': '#pipotronic', 'data': None, 'cmd': 'eddy_malou'},)
handle: Handle(<bound method event.async_callback of <bound event :(?P<mask>\S+) PRIVMSG (?P<target>\S+) :{re_cmd}(?P<cmd>\w+)(\s(?P<data>\S.*)|$) to <bound method Commands.on_command of <Commands ['!eddy_malou', '!help', '!ping', '!pipotronic']>>>>, ({'mask': '[email protected]', 'target': '#pipotronic', 'data': None, 'cmd': 'eddy_malou'},))
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/asyncio/events.py", line 39, in _run
    self._callback(*self._args)
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/dec.py", line 55, in async_callback
    return self.callback(**kwargs)
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/plugins/command.py", line 253, in on_command
    return self.do_command(predicates, meth, mask, target, **kw)
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/plugins/command.py", line 309, in do_command
    callback(res)
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/plugins/command.py", line 320, in command_callback
    handle = self.context.call_many('privmsg', iterator(msgs))
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/base.py", line 275, in call_many
    for i, arg in enumerate(args):
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/plugins/command.py", line 316, in iterator
    for msg in msgs:
  File "/home/jmcomets/Bundle/irc_bots/plugin.py", line 28, in eddy_malou
    msg = yield from pipeau.eddy_malou()
  File "/home/jmcomets/Bundle/irc_bots/pipeau.py", line 38, in eddy_malou
    page_source = yield from load_page_source_async('http://eddy-malou.com')
  File "/home/jmcomets/Bundle/irc_bots/pipeau.py", line 24, in load_page_source_async
    page_source = yield from loop.run_in_executor(None, load_page_source, url)
  File "/usr/local/lib/python3.4/asyncio/futures.py", line 349, in __iter__
    assert self.done(), "yield from wasn't used with future"
AssertionError: yield from wasn't used with future
ERROR asyncio    Exception in callback <bound method IrcBot.privmsg of <irc3.IrcBot object at 0x7ff8a280eb38>>('#pipotronic', Future<PENDING, [<function wrap_future.<locals>._check_cancel_other at 0x7ff8a23da488>]>)
handle: TimerHandle(97160.945039665, <bound method IrcBot.privmsg of <irc3.IrcBot object at 0x7ff8a280eb38>>, ('#pipotronic', Future<PENDING, [<function wrap_future.<locals>._check_cancel_other at 0x7ff8a23da488>]>))
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/asyncio/events.py", line 39, in _run
    self._callback(*self._args)
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/__init__.py", line 180, in privmsg
    for message in messages:
  File "/home/jmcomets/.local/lib/python3.4/site-packages/irc3/utils.py", line 114, in split_message
    if len(message) >= max_length:
TypeError: object of type 'Future' has no len()

Add Python 3.6 to tox.ini

Maybe it's time to add it to tox.ini? Don't know how much people are already using it, but my distri has it as default for a few months now.

Example code for DCC receive

Is there example code for a bot which is capable to receive DCC file transfers?
That would be really helpful.

Docopt command options_first flag, parsing negative numbers

For context, I'm working on porting a dicebot to use this library. Triggering this issue is that I'm attempting to create a command with a simple +/- numerical modifier. (example: !apoc -2, !apoc +1)

I've tracked this down to how IRC3 uses Docopt for command parsing, & how Docopt has an issue with using '-' to signal option commands. (docopt/docopt#158)

In the Docopt issue linked, there's a pair of workarounds provided which could work here:
Adding support for the options_first=True flag (added in Docopt 0.6.0), and adding the ability to modify an argument string as it comes in to prefix--.

I'm currently looking into how feasible this would be in the existing codebase, but at the least, adding the ability to flip the options_first flag would be an improvement.

A command's name should be able to be different than the method's name

It could be usefull to avoid some names collisions, for example to be able to create a !reload command with the new plugin reload system.

Exemple:

@command(name='reload', permission='admin')
def cmd_reload(self, mask, target, args):
    """
    Reload a plugin on the fly

    %%reload <plugins>...
    """
    self.bot.reload(*args['<plugins>'])

I made some changes locally in irc3/plugins/command.py and it seems to work, but I created a gist instead a pull request because I was not sure about the changes: https://gist.github.com/metathink/4a00a1d7bc9901781e08

SSL configuration option check_hostname missing

When trying to connect to Hackint with SSL I couldn't because it requires verify_mode CERT_NONE, which in turn needs check_hostname disabled, which seems to be impossible to set via the config.

The connection part of the config I can reproduce the error with:

[bot]
nick = irc3bot
username = irc3bot

host = irc.hackint.org
port = 9999

# uncomment this if you want ssl support
ssl = true
# uncomment this if you don't want to check the certificate
ssl_verify = CERT_NONE
check_hostname = false

The error thrown:

 in irc3/base.py", line 304, in get_ssl_context
    context.verify_mode = verify_mode
ValueError: Cannot set verify_mode to CERT_NONE when check_hostname is enabled.

DCC

Everyone likes DCC, right?

I think CHAT and SEND would cover most use cases.

Option to not keep trying new nick

I'm trying to write a client, but am finding the behaviour when the nick command fails a little frustrating.

As it currently stands, when the badnick method is called, a callback is set to retry the attempt again in 30 seconds. If the user picks a new nick in the interim (potentially a long time, as this callback is set repeatedly), and then the clashing nick disconnects, the user will get renamed, despite having already selected a new nick.

I would like to forego this behaviour in my client but, as far as I can tell, I cannot remove this one line without duplicating the whole module into my program, as if I were to subclass the module, the old method would already have been registered as an event.

Have I missed something --- is there a cleaner way for me to do this?

If there is no obvious way to fix this at the moment, I wonder if it would be desirable for me to refactor this module in some way to allow for easier extension, and if there are any suggestions for how I might proceed?

Thanks for taking the time to read this --- sorry that the report is little long!

utils.split_message strips control characters

split_message uses .strip(), which removes whitespace. Unfortunately, '\x1f', which is used to set underline, is the 'unit seperator' and thus counts as whitespace. This means a message that starts with underlined text does not show up as underlined.

This is also true for '\x1d' (italic). '\x02' (bold), '\x03' (color), '\x0f' (reset) and '\x16' (reverse colors) are not whitespace.

Bouncer support?

I'm having a problem with irc3 and ZNC, the problem being that irc3 connects perfectly, but it doesn't join any channels and it doesn't receive or send messages for the channels the bouncer is in, which in theory should also be channels the bot is in due to the way a bouncer works. Is this a bug, or a problem with the way I'm using irc3?

Prevent newline-based IRC injection

irc3 should not allow newlines to be inserted via command parameters, as this can cause IRC command injection.

For example,

bot.privmsg(chan, text)

with text="\nJOIN #channel"

would make the bot join #channel. Newlines could either be replaced by spaces, '\n' or dropped altogether (but I think spaces are probably the best option).

create_connection(loop=...) is not always respected

IrcBot.create_connection currently only calls loop.create_connection when it first connects. Also, the Task is run using the loop returned by get_event_loop() because the loop to run in is never specified in the Task constructor. On connection_lost, the loop is completely shifted over to the result of get_event_loop().

I propose shifting the loop argument to another function. The constructor, a set_loop() function, or a loop property would all work. When create_connection is called, it would then use self.loop. The protocol would call self.factory.create_connection(protocol=self.class) in connection_lost.

Multiple room message not sending

I am doing a multi-room message plugin using the following code:

from irc3.plugins.command import command
from irc3.compat import asyncio
import irc3

@irc3.plugin
class CabotPlugin(object):
    def __init__(self, bot):
        self.bot = bot

    @irc3.event(irc3.rfc.JOIN)
    def connect(self, mask, channel, **kw):
        print channel
        print self.bot.config.room_count
        # log only when the bot connect and disconect right after
        if mask.nick == self.bot.nick:
            print self.bot.config.message
            self.bot.privmsg(channel, self.bot.config.message)

        self.disconnect()

    def disconnect(self):
        self.bot.quit()
        self.bot.config.room_count -= 1
        if self.bot.config.room_count <= 0:
            self.bot.config.end_callback.set_result('OK')


def bootstrapIrc3():
    loop = asyncio.get_event_loop()
    end_callback = asyncio.Future()

    rooms = ['Room1_test', 'Room2_test']


    config = dict(
        host='sinisalo.freenode.net',
        port=6667,
        nick='the_bot_name',
        autojoins=rooms,
        room_count=len(rooms),
        message='the message'
    )
    # save the end method to be called after posting the message
    config['end_callback'] = end_callback
    config['includes'] = [__name__]

    # Create the bot and run it once
    sender = irc3.IrcBot.from_config(config)
    sender.run(forever=False)

    # set the asyncio resolve Future
    loop.run_until_complete(end_callback)

bootstrapIrc3()

As you can see, I create a bot that connects to two rooms and react on the JOIN event:
If the current joined user is the bot, send a message.
Then call the disconnect method, that decrease the room_count value to really disconnect only after all messages have been posted.

Output:

INFO irc3.the_bot_name Trying to join #Room1_test
INFO irc3.the_bot_name Trying to join #Room2_test
#Room1_test
2
the message
#Room2_test
1
the message

But the message never appears on the second room.

Do you know what the trouble can be ?
Thanks !

Using python 2.7, plugins without "explicit features" do not get loaded.

I noticed that irc3 does not load plugins if they do not contain any "explicit features" (like @extend), but only overwrite functions like connection_made or server_ready. To illustrate and reproduce this issue, execute the following code with both Python 2.7 and Python 3:

import irc3
import random


@irc3.plugin
class PluginA:
    def __init__(self, bot):
        self.bot = bot
        self.log = self.bot.log
        print("A got loaded!")

    def connection_made(self):
        print("A did something important.")

    @irc3.extend
    def i_do_not_serve_any_purpose_whatsoever(self):
        pass


@irc3.plugin
class PluginB:
    def __init__(self, bot):
        self.bot = bot
        self.log = self.bot.log
        print("B got loaded!")

    def connection_made(self):
        print("B did something important.")


def main():
    # instanciate a bot
    config = dict(
        nick='justinfan%d' % random.randint(1, 99999999),
        host="irc.twitch.tv", port=6667,
        includes=[
            __name__,  # this register MyPlugin
            ]
    )
    bot = irc3.IrcBot.from_config(config)
    bot.run(forever=True)

if __name__ == '__main__':
    main()

Output with Python 2.7.10, surprisingly:

A got loaded!
A did something important.

Output with Python 3.5.0, as expected:

A got loaded!
B got loaded!
A did something important.
B did something important.

Plugin to save data on disk

Sometime we want to be able to save data on disk for a plugin (say: the list of person to ping at a certain time).

It would be nice if irc3 could provide a framework to retrieve/save data on the disk.

Maybe storing the infos as dict and reading/saving it as json ?

irc3 and celery

hi, I'm executing an irc3 bot inside a celery task. The bot correctly connects to the server but it doesn't auto connect to the channels. And it behaves in a strange way with my plugin (a plugin to print received messages): it works for the first few messages received, then nothing happens.
And it doesn't answer to pings.

If I run my code directly and not inside a celery task it works perfectly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.