From 6c45d76b56f791a0275c4bd18ce2c00d9ea19352 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 24 Feb 2014 00:37:32 +0100 Subject: [PATCH] Made irc bot connect, but scripthandler lookup is causing traceback when searching for a player) --- src/commands/default/comms.py | 12 +++++++-- src/comms/comms.py | 8 ++---- src/locks/lockhandler.py | 2 ++ src/players/bots.py | 17 +++++++----- src/players/models.py | 2 +- src/scripts/manager.py | 11 +++++++- src/scripts/scripthandler.py | 13 ++++++--- src/server/amp.py | 2 ++ src/server/portal/irc.py | 32 +++++++++++++---------- src/server/portal/portalsessionhandler.py | 5 ++-- src/server/sessionhandler.py | 3 +-- 11 files changed, 70 insertions(+), 37 deletions(-) diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index 1dd7008cbe..5a65162be8 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -826,7 +826,7 @@ class CmdIRC2Chan(MuxCommand): if('disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches): - matches = PlayerDB.filter(db_isbot=True, db_key=botname) + matches = PlayerDB.objects.filter(db_is_bot=True, db_key=botname) if matches: matches[0].delete() self.msg("IRC connection destroyed.") @@ -835,7 +835,15 @@ class CmdIRC2Chan(MuxCommand): return # create a new bot - bot = create.create_player(botname, None, None, typeclass=bots.IRCBot) + bot = PlayerDB.objects.filter(username__iexact=botname) + if bot: + # re-use an existing bot + bot = bot[0].typeclass + if not bot.is_bot: + self.msg("Player '%s', which is not a bot, already exists." % botname) + return + else: + bot = create.create_player(botname, None, None, typeclass=bots.IRCBot) bot.start(ev_channel=channel, irc_botname=irc_botname, irc_channel=irc_channel, irc_network=irc_network, irc_port=irc_port) self.msg("Connection created. Starting IRC bot.") diff --git a/src/comms/comms.py b/src/comms/comms.py index 88d20519bb..d1cc2aef80 100644 --- a/src/comms/comms.py +++ b/src/comms/comms.py @@ -172,12 +172,8 @@ class Channel(TypeClass): # note our addition of the from_channel keyword here. This could be checked # by a custom player.msg() to treat channel-receives differently. player.msg(msg.message, from_obj=msg.senders, from_channel=self.id) - except AttributeError: - try: - player.to_external(msg.message, - senders=msg.senders, from_channel=self) - except Exception: - logger.log_trace("Cannot send msg to connection '%s'" % player) + except AttributeError, e: + logger.log_trace("%s\nCannot send msg to connection '%s'" % (e, player)) def msg(self, msgobj, header=None, senders=None, sender_strings=None, persistent=False, online=False, emit=False, external=False): diff --git a/src/locks/lockhandler.py b/src/locks/lockhandler.py index b2c9da731b..992ba051a7 100644 --- a/src/locks/lockhandler.py +++ b/src/locks/lockhandler.py @@ -201,6 +201,8 @@ class LockHandler(object): elist = [] # errors wlist = [] # warnings for raw_lockstring in storage_lockstring.split(';'): + if not raw_lockstring: + continue lock_funcs = [] try: access_type, rhs = (part.strip() for part in raw_lockstring.split(':', 1)) diff --git a/src/players/bots.py b/src/players/bots.py index aee37a3700..41ec74e0b2 100644 --- a/src/players/bots.py +++ b/src/players/bots.py @@ -31,7 +31,7 @@ class BotStarter(Script): def at_start(self): "Kick bot into gear" if not self.db.started: - self.obj.start() + self.player.start() self.db.started = False def at_server_reload(self): @@ -56,7 +56,7 @@ class CmdBotListen(Command): key = CMD_NOMATCH def func(self): - text = self.cmdname + self.args + text = self.cmdstring + self.args self.obj.execute_cmd(text, sessid=self.sessid) @@ -84,7 +84,7 @@ class Bot(Player): # the text encoding to use. self.db.encoding = "utf-8" # A basic security setup - lockstring = "examine:perm(Wizards);edit:perm(Wizards);delete:perm(Wizards);boot:perm(Wizards);msg:all()" + lockstring = "examine:perm(Wizards);edit:perm(Wizards);delete:perm(Wizards);boot:perm(Wizards);msg:false()" self.locks.add(lockstring) # set the basics of being a bot self.cmdset.add_default(BotCmdSet) @@ -134,12 +134,16 @@ class IRCBot(Bot): # if keywords are given, store (the BotStarter script # will not give any keywords, so this should normally only # happen at initialization) - self.db.irc_botname = irc_botname if irc_botname else self.key + if irc_botname: + self.db.irc_botname = irc_botname + elif not self.db.irc_botname: + self.db.irc_botname = self.key if ev_channel: # connect to Evennia channel channel = search.channel_search(ev_channel) if not channel: raise RuntimeError("Evennia Channel '%s' not found." % ev_channel) + channel = channel[0] channel.connect(self) self.db.ev_channel = channel if irc_channel: @@ -154,11 +158,12 @@ class IRCBot(Bot): # instruct the server and portal to create a new session with # the stored configuration - configdict = {"botname": self.db.irc_botname, + configdict = {"uid":self.dbid, + "botname": self.db.irc_botname, "channel": self.db.irc_channel , "network": self.db.irc_network, "port": self.db.irc_port} - _SESSIONS.start_bot_session("src.server.portal.irc.IRCClient", self.id, configdict) + _SESSIONS.start_bot_session("src.server.portal.irc.IRCBotFactory", configdict) def msg(self, text=None, **kwargs): """ diff --git a/src/players/models.py b/src/players/models.py index 94ffc7adf1..c4133f8bb3 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -415,7 +415,7 @@ class PlayerDB(TypedObject, AbstractUser): # deleting command) self.unpuppet_object(session.sessid) session.sessionhandler.disconnect(session, reason=_("Player being deleted.")) - + self.scripts.stop() super(PlayerDB, self).delete(*args, **kwargs) def execute_cmd(self, raw_string, sessid=None): diff --git a/src/scripts/manager.py b/src/scripts/manager.py index 4735a8eb1a..e87d110639 100644 --- a/src/scripts/manager.py +++ b/src/scripts/manager.py @@ -44,13 +44,22 @@ class ScriptManager(TypedObjectManager): if not obj: return [] obj = obj.dbobj + player = obj.__class__.__name__ == "PlayerDB" + print "get_all_scripts_on_obj:", obj, player if key: dbref = self.dbref(key) if dbref or dbref == 0: - script = self.filter(db_obj=obj, id=dbref) + if player: + script = self.filter(db_player=obj, id=dbref) + else: + script = self.filter(db_obj=obj, id=dbref) if script: return script + elif player: + return self.filter(db_player=obj, db_key=key) return self.filter(db_obj=obj.dbobj, db_key=key) + if player: + self.filter(db_player=obj) return self.filter(db_obj=obj) @returns_typeclass_list diff --git a/src/scripts/scripthandler.py b/src/scripts/scripthandler.py index bc53f143e2..b14ad89988 100644 --- a/src/scripts/scripthandler.py +++ b/src/scripts/scripthandler.py @@ -58,7 +58,13 @@ class ScriptHandler(object): definition) autostart - start the script upon adding it """ - script = create.create_script(scriptclass, key=key, obj=self.obj, + if self.obj.dbobj.__class__.__name__ == "PlayerDB": + # we add to a Player, not an Object + script = create.create_script(scriptclass, key=key, player=self.obj, + autostart=autostart) + else: + # the normal - adding to an Object + script = create.create_script(scriptclass, key=key, obj=self.obj, autostart=autostart) if not script: logger.log_errmsg("Script %s could not be created and/or started." % scriptclass) @@ -75,12 +81,13 @@ class ScriptHandler(object): num += script.start() return num - def delete(self, scriptid): + def delete(self, scriptid=None): """ Forcibly delete a script from this object. scriptid can be a script key or the path to a script (in the latter case all scripts with this path will be deleted!) + If no scriptid is set, delete all scripts on the object. """ delscripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=scriptid) @@ -91,7 +98,7 @@ class ScriptHandler(object): num += script.stop() return num - def stop(self, scriptid): + def stop(self, scriptid=None): """ Alias for delete. scriptid can be a script key or a script path string. """ diff --git a/src/server/amp.py b/src/server/amp.py index 5d1d9740bd..e529f7c208 100644 --- a/src/server/amp.py +++ b/src/server/amp.py @@ -472,8 +472,10 @@ class AMPProtocol(amp.AMP): portal_sessionhandler.server_session_sync(data) # set a flag in case we are about to shut down soon self.factory.server_restart_mode = True + elif operation == SCONN: # server_force_connection (for irc/imc2 etc) portal_sessionhandler.server_connect(**data) + else: raise Exception("operation %(op)s not recognized." % {'op': operation}) return {} diff --git a/src/server/portal/irc.py b/src/server/portal/irc.py index dbf4b3e01f..6e932b7dde 100644 --- a/src/server/portal/irc.py +++ b/src/server/portal/irc.py @@ -30,11 +30,16 @@ class IRCBot(irc.IRCClient, Session): def signedOn(self): """ This is called when we successfully connect to - the network. We make sure to store ourself - on the factory. + the network. We make sure to now register with + the game as a full session. """ self.join(self.channel) self.factory.bot = self + self.init_session("ircbot", self.network, self.factory.sessionhandler) + # we link back to our bot and log in + self.uid = self.factory.uid + self.logged_in = True + self.factory.sessionhandler.connect(self) def privmsg(self, user, channel, msg): "A message was sent to channel" @@ -55,11 +60,6 @@ class IRCBot(irc.IRCClient, Session): "Data from server-> IRC" self.say(self.channel, text) - def start(self): - "Connect session to sessionhandler" - service = internet.TCPClient(self.network, int(self.port), self) - self.sessionhandler.portal.services.addService(service) - self.sessionhandler.connect(self) class IRCBotFactory(protocol.ReconnectingClientFactory): """ @@ -71,14 +71,14 @@ class IRCBotFactory(protocol.ReconnectingClientFactory): factor = 1.5 maxDelay = 60 - def __init__(self, botname=None, channel=None, network=None, port=None): + def __init__(self, uid=None, botname=None, channel=None, network=None, port=None): "Storing some important protocol properties" - self.nickname = botname - self.logger = logger - self.channel = channel - self.network = network - self.port = port - self.bots = None + self.uid = int(uid) + self.nickname = str(botname) + self.channel = str(channel) + self.network = str(network) + self.port = int(port) + self.bot = None def buildProtocol(self, addr): "Build the protocol and assign it some properties" @@ -94,6 +94,10 @@ class IRCBotFactory(protocol.ReconnectingClientFactory): "Tracks reconnections for debugging" logger.log_infomsg("(re)connecting to %s" % self.channel) + def start(self): + "Connect session to sessionhandler" + service = internet.TCPClient(self.network, self.port, self) + self.sessionhandler.portal.services.addService(service) # diff --git a/src/server/portal/portalsessionhandler.py b/src/server/portal/portalsessionhandler.py index 05ff99fb9f..d09732f3c6 100644 --- a/src/server/portal/portalsessionhandler.py +++ b/src/server/portal/portalsessionhandler.py @@ -69,7 +69,7 @@ class PortalSessionHandler(SessionHandler): operation=PDISCONN) - def server_connect(self, protocol_path="", uid=None, config=dict()): + def server_connect(self, protocol_path="", config=dict()): """ Called by server to force the initialization of a new protocol instance. Server wants this instance to get @@ -79,7 +79,6 @@ class PortalSessionHandler(SessionHandler): protocol_path - full python path to the class factory for the protocol used, eg 'src.server.portal.irc.IRCClientFactory' - uid - database uid to the connected player-bot config - dictionary of configuration options, fed as **kwarg to protocol class' __init__ method. @@ -91,6 +90,8 @@ class PortalSessionHandler(SessionHandler): from src.utils.utils import variable_from_module as _MOD_IMPORT path, clsname = protocol_path.rsplit(".", 1) cls = _MOD_IMPORT(path, clsname) + if not cls: + raise RuntimeError("ServerConnect: protocol factory '%s' not found." % protocol_path) protocol = cls(**config) protocol.sessionhandler = self protocol.start() diff --git a/src/server/sessionhandler.py b/src/server/sessionhandler.py index 38cd1d7ece..8f0bdfd29a 100644 --- a/src/server/sessionhandler.py +++ b/src/server/sessionhandler.py @@ -259,7 +259,7 @@ class ServerSessionHandler(SessionHandler): # server-side access methods - def start_bot_session(self, protocol_path, uid, configdict): + def start_bot_session(self, protocol_path, configdict): """ This method allows the server-side to force the Portal to create a new bot session using the protocol specified by protocol_path, @@ -271,7 +271,6 @@ class ServerSessionHandler(SessionHandler): Server. """ data = {"protocol_path":protocol_path, - "uid":uid, "config":configdict} self.server.amp_protocol.call_remote_PortalAdmin(0, operation=SCONN,