gawel / irc3

plugable irc client library based on python's asyncio with DCC and SASL support
https://irc3.readthedocs.io/
MIT License
208 stars 46 forks source link

DCC GET seems not work #182

Closed DarkSkull91 closed 4 years ago

DarkSkull91 commented 4 years ago

Hi,

I can't understand if I misunderstood how the dcc_get works. Many channels use commands like this to start download a file: /msg ChannelBOT xdcc send #1250 so I send this message on the JOIN event, I see the message sent on the channel but the download doesn't start. Where am i wrong?

gawel commented 4 years ago

Try to start the bot with -vd arguments and see what's hapenning. Can't really help more without code snippets

DarkSkull91 commented 4 years ago

I don't run with the command irc3 config.ini but like a python script. Here is my code:

# -*- coding: utf-8 -*-
from irc3.compat import asyncio
from irc3d import IrcServer
import irc3

@irc3.plugin
class Plugin(object):

    def __init__(self, context):
        self.log = context.log
        self.context = context

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        self.context.join('#channel')

    @irc3.event(irc3.rfc.JOIN)
    def join(self, mask=None, **kw):
        self.context.privmsg("#channel", "Hi!')
        self.context.privmsg("#channel", "!list')
        self.context.privmsg("#channel", '/msg bot_name xdcc send #1250')
        can_download = True

    @irc3.event(irc3.rfc.CTCP)
    async def on_ctcp(self, mask=None, **kwargs):    
        # parse ctcp message
        if can_download == True:
            name = "file.pdf"
            host = "irc.server.net"
            port = 6667
            size = 330560 # this is in byte, is it correct?
            self.context.log.info('%s is offering %s', mask.nick, name)
            # get the file
            conn = await self.context.create_task(self.context.dcc_get(
                mask, host, port, './'+name, int(size)))
            await conn.closed
            # parse ctcp message
            self.context.log.info('file received from %s', mask.nick)

def main():
    global can_download
    cfg = dict(
        host='irc.oltreirc.net',
        autojoins=['#channel'],
        port=6667,
        nick='geppetto82',
        includes=['irc3.plugins.core',"irc3.plugins.uptime","irc3.plugins.ctcp", 'irc3.plugins.dcc', __name__]
    )
    can_download = False

    receiver = irc3.IrcBot.from_config(cfg)
    receiver.run(forever=True)

if __name__ == '__main__':
    main()

I use can_download because the first ctcp messages comes when the bot connects to the server. Where am I wrong?

gawel commented 4 years ago

You still can use verbose/debug=true in your bot config

This is not how dcc works. You cant define host/port by yourself. You need to use those sent by the bot. Check https://github.com/gawel/irc3/blob/master/examples/dcc_send_and_get.py#L27

DarkSkull91 commented 4 years ago

I edit my bot in this way but I can't still receive no data. I removed the sender and server related code because I think I don't need it. Now, my code is like this:

# -*- coding: utf-8 -*-
from irc3.compat import asyncio
from irc3d import IrcServer
import irc3

@irc3.plugin
class Plugin(object):

    def __init__(self, context):
        self.log = context.log
        self.context = context

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        self.context.join('#channel')

    @irc3.event(irc3.rfc.JOIN)
    async def join(self, mask, channel, **kw):
        self.context.privmsg(channel, '/msg bot_channel xdcc send #934')

    @irc3.event(irc3.rfc.CTCP)
    async def on_ctcp(self, mask=None, **kwargs):
        # parse ctcp message
        name, host, port, size = kwargs['ctcp'].split()[2:]
        self.context.log.info('%s is offering %s', mask.nick, name)
        # get the file
        conn = await self.context.create_task(self.context.dcc_get(
            mask, host, port, './' + name, int(size)))
        await conn.closed
        self.context.log.info('file received from %s', mask.nick)

        # end loop by setting future's result
        self.context.config.file_received.set_result(True)

def main():
    loop = asyncio.get_event_loop()

    cfg = dict(
        host='irc.server.net',
        port=6667,
        nick='mynick',
        includes=['irc3.plugins.core', "irc3.plugins.ctcp", 'irc3.plugins.dcc', __name__],
        loop=loop,
        verbose=True,
        debug=True
    )

    file_received = asyncio.Future()

    # assume receiver is created *after* sender
    receiver = irc3.IrcBot.from_config(cfg,file_received=file_received)

    # this bot will receive the file
    receiver.run(forever=False)
    loop.run_until_complete(file_received)

if __name__ == '__main__':
    main()

but I got this exception

ERROR asyncio    Task exception was never retrieved
future: <Task finished coro=<Plugin.on_ctcp() done, defined at dcc_send_and_get.py:25> exception=ValueError('not enough values to unpack (expected 4, got 0)')>
Traceback (most recent call last):
  File "dcc_send_and_get.py", line 29, in on_ctcp
    name, host, port, size = kwargs['ctcp'].split()[2:]
ValueError: not enough values to unpack (expected 4, got 0)

I see the message sent on the join channel, but I don't receive any file. What am I wrong?

gawel commented 4 years ago

First you should match only DCC on ctcp: if 'DCC' in kwargs['ctcp']

And you should send the dcc send message to the bot, not to the channel, I guess

DarkSkull91 commented 4 years ago

@gawel, you're great man, it works. Thank you for your support!