lizmat / IRC-Client

Raku module for building IRC (Internet Relay Chat) clients
Artistic License 2.0
14 stars 7 forks source link

[RFC] Extra Information in Filters #20

Open MasterDuke17 opened 7 years ago

MasterDuke17 commented 7 years ago

In :filters( -> $text where .lines > 1 || .chars > 300 { } ), $text is just a string, so you can't access any attributes or methods of the current IRC::Client::Message. For example, if you wanted to put your current nickname (which could be different per server) in the $text you would need access to IRC::Client::Message.server.current-nick.

zoffixznet commented 7 years ago

Would you have a concrete example of what you're trying to accomplish?

Currently, I'm leaning towards rejecting this proposal, however, I'm open to making changes if a solution that makes sense is found.

The biggest concern is :filters operate further down the pipeline, pretty much at the place where the message is about to hit the wire. So IRC::Client::Message isn't always available. For example, consider this plugin:

class Plug does IRC::Client::Plugin {
    method irc-started {
        start react {
            whenever Supply.interval(3) {
                $.irc.send: :where<Zoffix> :text("Notice me!!");
            }
        }
    }
}

The filters will still be hit, but there's no IRC::Client::Message and never was one.

Perhaps it's the IRC::Client::Server to which the message is going to, rather than IRC::Client::Message, that should be added. However, that introduces another problem for multi-server messages as the filter (currently) runs just once per message, not per server the message is going out to.

My original idea for filters was pretty much limited to just pastebinning output that's too large for IRC, so that's why I want to know what you're trying to use filters for.

AlexDaniel commented 7 years ago

My original idea for filters was pretty much limited to just pastebinning output that's too large for IRC, so that's why I want to know what you're trying to use filters for.

Surprisingly, we are trying to do exactly the same thing. However, bisectable/committable gists include the message itself (pasted as a separate file) and the nickname of the bot. For example, see this gist.

Arguably, we can do without it, but that's a bit less than awesome. For that reason I hacked something for perl 6 version of committable: see this and this.

Basically the idea is to subclass Str and add the missing Message field. Then we can cross our fingers and hope that exactly the same object will end up in the filter, and surprisingly it is so! So it kinda works now, but it would be less scary if it was provided by IRC::Client module.

zoffixznet commented 7 years ago

I've just realized the filters receive whatever is sent. It doesn't have to be a Str, it can be almost any object. The only things that currently get ignored are the IRC::Client | Supply | Channel and you can't send a Promise to a filter, since it gets automatically awaited.

So below, I'm passing a Hash with the "result" of what the bot does as well as the original IRC::Client::Message object.

If such use is documented, would that solve this Issue?

use IRC::Client;
.run with IRC::Client.new:
    :debug
    :plugins(class {
        method irc-to-me ($e) {
            { result => rand, message => $e }
        }
    })
    :filters(
        -> $e { "I'm $e<message>.server.current-nick() sending you $e<result>" }
    )

There also looks to be a dependency on #17 here, since filters' input might depend on how that Issue is resolved.

AlexDaniel commented 7 years ago

Yes. I think it can be closed once it is documented. However, I think the Message object should be passed to the filter by default (or should be available in some sort of variable), simply because it is way too common (and also because I'm annoyed by the fact that i have to mix in the Message object to whatever I am returning, everywhere).