diff --git a/classes.py b/classes.py index 9190048..80dcd40 100644 --- a/classes.py +++ b/classes.py @@ -256,7 +256,6 @@ class Irc(): # All our checks passed, get the protocol module to connect # and run the listen loop. self.proto.connect() - self.spawnMain() log.info('(%s) Starting ping schedulers....', self.name) self.schedulePing() log.info('(%s) Server ready; listening for data.', self.name) @@ -433,23 +432,6 @@ class Irc(): log.debug('(%s) Ping scheduled at %s', self.name, time.time()) - def spawnMain(self): - """Spawns the main PyLink client.""" - nick = self.botdata.get('nick') or 'PyLink' - ident = self.botdata.get('ident') or 'pylink' - host = self.serverdata["hostname"] - log.info('(%s) Connected! Spawning main client %s.', self.name, nick) - olduserobj = self.pseudoclient - self.pseudoclient = self.proto.spawnClient(nick, ident, host, - modes={("+o", None)}, - manipulatable=True, - opertype="PyLink Service") - for chan in self.serverdata['channels']: - self.proto.join(self.pseudoclient.uid, chan) - # PyLink internal hook called when spawnMain is called and the - # contents of Irc().pseudoclient change. - self.callHooks([self.sid, 'PYLINK_SPAWNMAIN', {'olduser': olduserobj}]) - def __repr__(self): return "" % self.name @@ -459,22 +441,7 @@ class Irc(): Calls a PyLink bot command. source is the caller's UID, and text is the full, unparsed text of the message. """ - cmd_args = text.strip().split(' ') - cmd = cmd_args[0].lower() - cmd_args = cmd_args[1:] - if cmd not in world.commands: - self.msg(self.called_by or source, 'Error: Unknown command %r.' % cmd) - log.info('(%s) Received unknown command %r from %s', self.name, cmd, self.getHostmask(source)) - return - log.info('(%s) Calling command %r for %s', self.name, cmd, self.getHostmask(source)) - for func in world.commands[cmd]: - try: - func(self, source, cmd_args) - except utils.NotAuthenticatedError: - self.msg(self.called_by or source, 'Error: You are not authorized to perform this operation.') - except Exception as e: - log.exception('Unhandled exception caught in command %r', cmd) - self.msg(self.called_by or source, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e))) + world.services['pylink'].call_cmd(self, source, text) def msg(self, target, text, notice=False, source=None): """Handy function to send messages/notices to clients. Source @@ -1129,7 +1096,6 @@ class FakeIRC(Irc): self.hookmsgs = [] self.socket = None self.initVars() - self.spawnMain() self.connected = threading.Event() self.connected.set() diff --git a/coreplugin.py b/coreplugin.py index ea84f34..e85157c 100644 --- a/coreplugin.py +++ b/coreplugin.py @@ -40,11 +40,6 @@ signal.signal(signal.SIGTERM, sigterm_handler) def handle_kill(irc, source, command, args): """Handle KILLs to PyLink service bots, respawning them as needed.""" target = args['target'] - - if target == irc.pseudoclient.uid: - irc.spawnMain() - return - for name, sbot in world.services.items(): if target == sbot.uids.get(irc.name): spawn_service(irc, source, command, {'name': name}) @@ -55,8 +50,7 @@ def handle_kick(irc, source, command, args): """Handle KICKs to the PyLink service bots, rejoining channels as needed.""" kicked = args['target'] channel = args['channel'] - if kicked == irc.pseudoclient.uid or kicked in \ - [sbot.uids.get(irc.name) for sbot in world.services.values()]: + if kicked in [sbot.uids.get(irc.name) for sbot in world.services.values()]: irc.proto.join(kicked, channel) utils.add_hook(handle_kick, 'KICK') @@ -65,14 +59,10 @@ def handle_commands(irc, source, command, args): target = args['target'] text = args['text'] - if target == irc.pseudoclient.uid and not irc.isInternalClient(source): - irc.called_by = source - irc.callCommand(source, text) - else: - for sbot in world.services.values(): - if target == sbot.uids.get(irc.name): - sbot.call_cmd(irc, source, text) - return + for sbot in world.services.values(): + if target == sbot.uids.get(irc.name): + sbot.call_cmd(irc, source, text) + return utils.add_hook(handle_commands, 'PRIVMSG') @@ -223,9 +213,16 @@ def spawn_service(irc, source, command, args): # Track the service's UIDs on each network. sbot = world.services[name] - sbot.uids[irc.name] = u = irc.proto.spawnClient(sbot.nick, sbot.ident, + userobj = irc.proto.spawnClient(sbot.nick, sbot.ident, host, modes=modes, opertype="PyLink Service", - manipulatable=sbot.manipulatable).uid + manipulatable=sbot.manipulatable) + + sbot.uids[irc.name] = u = userobj.uid + + # Special case: if this is the main PyLink client being spawned, + # assign this as irc.pseudoclient. + if name == 'pylink': + irc.pseudoclient = userobj # TODO: channels should be tracked in a central database, not hardcoded # in conf. @@ -256,6 +253,11 @@ def handle_endburst(irc, source, command, args): utils.add_hook(handle_endburst, 'ENDBURST') +# Register the main PyLink service. All command definitions MUST go after this! +mynick = conf.conf['bot'].get("nick", "PyLink") +myident = conf.conf['bot'].get("ident", "pylink") +utils.registerService('pylink', nick=mynick, ident=myident) + # Essential, core commands go here so that the "commands" plugin with less-important, # but still generic functions can be reloaded. @@ -465,4 +467,3 @@ def rehash(irc, source, args): return else: irc.reply("Done.") - diff --git a/plugins/commands.py b/plugins/commands.py index 5b378cc..84e6bdb 100644 --- a/plugins/commands.py +++ b/plugins/commands.py @@ -20,53 +20,6 @@ def status(irc, source, args): irc.reply('You are not identified as anyone.') irc.reply('Operator access: \x02%s\x02' % bool(irc.isOper(source))) -def listcommands(irc, source, args): - """takes no arguments. - - Returns a list of available commands PyLink has to offer.""" - cmds = list(world.commands.keys()) - cmds.sort() - for idx, cmd in enumerate(cmds): - nfuncs = len(world.commands[cmd]) - if nfuncs > 1: - cmds[idx] = '%s(x%s)' % (cmd, nfuncs) - irc.reply('Available commands include: %s' % ', '.join(cmds)) - irc.reply('To see help on a specific command, type \x02help \x02.') -utils.add_cmd(listcommands, 'list') - -@utils.add_cmd -def help(irc, source, args): - """ - - Gives help for , if it is available.""" - try: - command = args[0].lower() - except IndexError: # No argument given, just return 'list' output - listcommands(irc, source, args) - return - if command not in world.commands: - irc.msg(source, 'Error: Unknown command %r.' % command) - return - else: - funcs = world.commands[command] - if len(funcs) > 1: - irc.reply('The following \x02%s\x02 plugins bind to the \x02%s\x02 command: %s' - % (len(funcs), command, ', '.join([func.__module__ for func in funcs]))) - for func in funcs: - doc = func.__doc__ - mod = func.__module__ - if doc: - lines = doc.split('\n') - # Bold the first line, which usually just tells you what - # arguments the command takes. - lines[0] = '\x02%s %s\x02 (plugin: %r)' % (command, lines[0], mod) - for line in lines: - irc.reply(line.strip()) - else: - irc.msg(source, "Error: Command %r (from plugin %r) " - "doesn't offer any help." % (command, mod)) - return - _none = '\x1D(none)\x1D' @utils.add_cmd def showuser(irc, source, args): diff --git a/utils.py b/utils.py index 4d447fb..9431497 100644 --- a/utils.py +++ b/utils.py @@ -65,10 +65,7 @@ class IncrementalUIDGenerator(): def add_cmd(func, name=None): """Binds an IRC command function to the given command name.""" - if name is None: - name = func.__name__ - name = name.lower() - world.commands[name].append(func) + world.services['pylink'].add_cmd(func, name=name) return func def add_hook(func, command):