MegBot icon indicating copy to clipboard operation
MegBot copied to clipboard

Plugin conflicts

Open moggers87 opened this issue 9 years ago • 2 comments

We need some way of making a plugin "greedy" or maybe just ignore !command messages.

moggers87 avatar Feb 12 '16 18:02 moggers87

It seems this effects many plugins not just beertime and 8ball. As discussed on IRC :)

I have a solution where an additional attribute can be included in the Info object. The attribute will reflect if a plugin is (going to be) called. On an empty Info object (which you use to register events) this will default to False, so by default events are not called if a plugin is called. This seems to be the most megbot-like solution, we're already using the Info object to tell events when to trigger or not.

The obvious problem is how do you handle it when you want both to be called when a plugin is called and when it isn't. It seems to me there are a few solutions to this:

  • Register your event twice: once with Info.triggered = False (the default) and one with Info.triggered = True
  • Allow attributes to take multiple values via tuples e.g. Info.triggered = (True, False) the downside to this is some attributes such as Info.nickmask are tuples, it's ambiguous and inconsistent. :-1:
  • I think my preference would be allow them to take a callable which returns if it matches, example of this with the seen plugin below:
def init(connection):
    eventID = 'seenEvent'
    info = connection.libraries["IRCObjects"].Info()

    # this will peform an event on privmsg.
    info.action = "PRIVMSG"
    info.triggered = lambda t: True # Always match on this value.
    event = connection.core["Corehandler"].IRCEvent(info, on_PRIVMSG, eventID)
    connection.handler.register_event(event)

With this solution in place: beertime wouldn't conflict with anything as it'd leave this as default, nor would reply. The scene plugin can be made to always log as it does now with a small additional change. We also keep the idea of Info being created to reflect when you want your event called.

tsyesika avatar Apr 14 '18 12:04 tsyesika

That means attaching plugin state onto the incoming Info object (otherwise how is the callable on Info.triggered?). I don't like that at all.

My personal preference would be if event handlers returned something, perhaps a truthy value:

def on_PRIV(conn, info):
    store.add_message(info)  # do something or other
    # implicit return None, which is falsey

def on_cmd(conn, info):
    who, what, when = store.get_user(info)
    info.channel.send("%s said %s on %s" % (who, what, when))
    return True

def init(connection):
    # register these event, order is important
    ## etc. etc. etc.

Then whatever is iterating over can do something like:

for callback in list_of_matching_callbacks:
   result = callback(conn, info)
   if result:
       break

moggers87 avatar Apr 14 '18 15:04 moggers87