New plugin prioritization method.

This commit is contained in:
Jeremy Fincher 2004-09-10 06:30:21 +00:00
parent 6243fe6baf
commit c573ab5996
4 changed files with 71 additions and 9 deletions

View File

@ -65,12 +65,16 @@ conf.registerGlobalValue(conf.supybot.plugins.Misc, 'listPrivatePlugins',
are loaded."""))
class Misc(callbacks.Privmsg):
priority = sys.maxint
def __init__(self):
super(Misc, self).__init__()
timeout = conf.supybot.abuse.flood.command.invalid
self.invalidCommands = ircutils.FloodQueue(timeout)
callAfter = utils.Everything()
callBefore = utils.Nothing()
def __cmp__(self, other):
return 1 # We should always be the last plugin.
def invalidCommand(self, irc, msg, tokens):
self.log.debug('Misc.invalidCommand called (tokens %s)', tokens)
# First, we check for invalidCommand floods. This is rightfully done

View File

@ -183,7 +183,6 @@ class LogProxy(object):
class Owner(privmsgs.CapabilityCheckingPrivmsg):
# This plugin must be first; its priority must be lowest; otherwise odd
# things will happen when adding callbacks.
priority = ~sys.maxint-1 # This must be first!
capability = 'owner'
_srcPlugins = ircutils.IrcSet(('Admin', 'Channel', 'Config',
'Misc', 'Owner', 'User'))
@ -227,6 +226,11 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
continue
registerDefaultPlugin(name, s)
callAfter = utils.Nothing()
callBefore = utils.Everything()
def __cmp__(self, other):
return -1 # We should always be the first plugin.
def _getIrc(self, network):
network = network.lower()
for irc in world.ircs:
@ -376,10 +380,12 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
def doPrivmsg(self, irc, msg):
callbacks.Privmsg.handled = False
callbacks.Privmsg.errored = False
if ircdb.checkIgnored(msg.prefix):
return
ignored = ircdb.checkIgnored(msg.prefix)
s = callbacks.addressed(irc.nick, msg)
if s:
if ignored:
self.log.info('Ignoring command from %s.' % msg.prefix)
return
brackets = conf.supybot.reply.brackets.get(msg.args[0])()
try:
tokens = callbacks.tokenize(s, brackets=brackets)
@ -595,17 +601,17 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
if name.endswith('.py'):
name = name[:-3]
if irc.getCallback(name):
irc.error('That plugin is already loaded.')
irc.error('%s is already loaded.' % name.capitalize())
return
try:
module = loadPluginModule(name, ignoreDeprecation)
except Deprecated:
irc.error('That plugin is deprecated. '
'Use --deprecated to force it to load.')
irc.error('%s is deprecated. Use --deprecated '
'to force it to load.' % name.capitalize())
return
except ImportError, e:
if name in str(e):
irc.error('No plugin %s exists.' % name)
irc.error('No plugin named %s exists.' % utils.dqrepr(name))
else:
irc.error(str(e))
return

View File

@ -570,6 +570,7 @@ class IrcObjectProxy(RichReplyMethods):
def finalEval(self):
assert not self.finalEvaled, 'finalEval called twice.'
self.finalEvaled = True
# We can't canonicalName here because it might be a regexp method.
name = self.args[0]
cbs = findCallbackForCommand(self, name)
if len(cbs) == 0:
@ -595,6 +596,9 @@ class IrcObjectProxy(RichReplyMethods):
# Ok, no regexp-based things matched.
self._callInvalidCommands()
else:
# But we must canonicalName here, since we're comparing to a
# canonicalName.
name = canonicalName(name)
if len(cbs) > 1:
for cb in cbs:
if canonicalName(cb.name()) == name:
@ -862,6 +866,8 @@ class Privmsg(irclib.IrcCallback):
alwaysCall = ()
threaded = False
noIgnore = False
callAfter = ()
callBefore = ()
Proxy = IrcObjectProxy
commandArgs = ['self', 'irc', 'msg', 'args']
# This must be class-scope, so all plugins use the same one.
@ -871,6 +877,10 @@ class Privmsg(irclib.IrcCallback):
self.__parent = super(Privmsg, self)
myName = self.name()
self.log = log.getPluginLogger(myName)
# We can't do this because of the specialness that Owner and Misc do.
# I guess plugin authors will have to get the capitalization right.
# self.callAfter = map(str.lower, self.callAfter)
# self.callBefore = map(str.lower, self.callBefore)
### Setup the dispatcher command.
canonicalname = canonicalName(myName)
self._original = getattr(self, canonicalname, None)
@ -919,6 +929,37 @@ class Privmsg(irclib.IrcCallback):
dispatcher.isDispatcher = True
setattr(self.__class__, canonicalname, dispatcher)
# In addition to priority, plugins may specify callBefore and callAfter
# attributes which are lists of plugin names which the plugin should be
# called before and after, respectively. We may, at some future point,
# remove priority entirely.
def __cmp__(self, other, doAssert=True):
selfName = self.name()
otherName = other.name()
# We can't be certain of the order the callbacks list is in, so we
# can't be certain that our __cmp__ is the most specific one, so
# we basically run the other callback's as well.
if isinstance(other, Privmsg):
if otherName in self.callAfter or selfName in other.callBefore:
ret = 1
elif otherName in self.callBefore or selfName in other.callAfter:
ret = -1
else:
ret = self.__parent.__cmp__(other)
else:
ret = self.__parent.__cmp__(other)
if doAssert:
try:
otherRet = other.__cmp__(self, doAssert=False)
except TypeError, e:
if 'doAssert' in str(e): # unexpected keyword argument.
otherRet = cmp(other, self)
else:
otherRet = ret
assert ret+otherRet==0, 'callbacks\' __cmp__ disagree: %s, %s' % \
(selfName, otherName)
return ret
def __call__(self, irc, msg):
if msg.command == 'PRIVMSG':
if self.noIgnore or not ircdb.checkIgnored(msg.prefix,msg.args[0]):

View File

@ -76,14 +76,23 @@ class IrcCallback(IrcCommandDispatcher):
# numbers mean *higher* priority (like nice values in *nix). Higher
# priority means the callback is called *earlier* on the inFilter chain,
# *earlier* on the __call__ chain, and *later* on the outFilter chain.
priority = 99
__metaclass__ = log.MetaFirewall
__firewalled__ = {'die': None,
'reset': None,
'__call__': None,
'__cmp__': lambda self: 0,
'inFilter': lambda self, irc, msg: msg,
'outFilter': lambda self, irc, msg: msg,
'name': lambda self: self.__class__.__name__,}
def __cmp__(self, other):
ret = cmp(self.priority, other.priority)
if not ret:
ret = cmp(self.name(), other.name())
return ret
def name(self):
"""Returns the name of the callback."""
return self.__class__.__name__
@ -586,7 +595,9 @@ class Irc(IrcCommandDispatcher):
def addCallback(self, callback):
"""Adds a callback to the callbacks list."""
self.callbacks.append(callback)
utils.sortBy(operator.attrgetter('priority'), self.callbacks)
self.callbacks.sort()
# We used to do this, then we implemented sorting in IrcCallback.
# utils.sortBy(operator.attrgetter('priority'), self.callbacks)
def getCallback(self, name):
"""Gets a given callback by name."""