From 25505d69a60ac91b289f4fe1e5bf589f32b6305c Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 17 Feb 2013 18:48:48 +0100 Subject: [PATCH] Moved login and disconnect from session-level to sessionhandler level to make the process cleaner with hooks rather than direct calls. --- src/commands/command.py | 35 ++++++++++++++---- src/commands/default/general.py | 24 ++++++++++--- src/commands/default/unloggedin.py | 6 ++-- src/objects/models.py | 9 +++-- src/players/models.py | 16 ++++++--- src/server/serversession.py | 58 +++++++----------------------- src/server/sessionhandler.py | 31 ++++++++++++++-- 7 files changed, 109 insertions(+), 70 deletions(-) diff --git a/src/commands/command.py b/src/commands/command.py index f7ce58ff38..f4b7e8caaa 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -118,14 +118,12 @@ class Command(object): # used by the help system to group commands in lists. help_category = "general" - # this normally does not need to be changed. It allows to turn off - # auto-help entry creation for individual commands. + # This allows to turn off auto-help entry creation for individual commands. auto_help = True - # There is also the property 'obj'. This gets set by the system - # on the fly to tie this particular command to a certain in-game entity. - # self.obj should NOT be defined here since it will not be overwritten - # if it already exists. - + # auto-set (by Evennia on command instantiation) are: + # obj - which object this command is defined on + # sessid - which session-id (if any) is responsible for triggering this command + # def __init__(self): "the lockhandler works the same as for objects." @@ -190,6 +188,29 @@ class Command(object): """ return self.lockhandler.check(srcobj, access_type, default=default) + def msg(self, msg="", data=None, from_obj=None, to_obj=None, all_sessions=False): + """ + This is a shortcut instad of calling msg() directly on an object - it will + determine + + detect if caller is an Object or a Player and also appends self.sessid + automatically. + + msg - text string of message to send + data - optional dictionary of data + from_obj - source of message. Defaults to self.caller. + to_obj - target object of message. Defaults to self.caller + all_sessions (bool) - default is to send only to the session connected to + the target object + """ + from_obj = from_obj or self.caller + to_obj = to_obj or from_obj + if hasattr(to_obj, "sessid"): + sessid = all_sessions and None or to_obj.sessid + else: + sessid = None + to_obj.msg(msg, from_obj=from_obj, data=data, sessid=sessid) + # Common Command hooks def at_pre_cmd(self): diff --git a/src/commands/default/general.py b/src/commands/default/general.py index 5511f627ce..ab453a4829 100644 --- a/src/commands/default/general.py +++ b/src/commands/default/general.py @@ -388,7 +388,11 @@ class CmdQuit(MuxCommand): Usage: @quit - Gracefully disconnect from the game. + Switch: + all - disconnect all connected sessions + + Gracefully disconnect your current session from the + game. Use the /all switch to disconnect from all sessions. """ key = "@quit" locks = "cmd:all()" @@ -400,10 +404,20 @@ class CmdQuit(MuxCommand): else: player = self.caller - player.msg("{RQuitting{n. Hope to see you soon again.", sessid=self.sessid) - player.disconnect_session_from_player(self.sessid) - #for session in self.caller.sessions: - # session.session_disconnect() + if 'all' in self.switches: + player.msg("{RQuitting{n all sessions. Hope to see you soon again.", sessid=self.sessid) + for session in player.get_all_sessions(): + player.disconnect_session_from_player(session.sessid) + else: + nsess = len(player.get_all_sessions()) + if nsess == 2: + player.msg("{RQuitting{n. One session is still connected.", sessid=self.sessid) + elif nsess > 2: + player.msg("{RQuitting{n. %i session are still connected." % (nsess-1), sessid=self.sessid) + else: + # we are quitting the last available session + player.msg("{RQuitting{n. Hope to see you soon again.", sessid=self.sessid) + player.disconnect_session_from_player(self.sessid) class CmdWho(MuxCommand): """ diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index b51ead4b7e..ac29d311e5 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -97,7 +97,7 @@ class CmdUnconnectedConnect(MuxCommand): # at_pre_login() # player.at_post_login() - calls look if no character is set # character.at_post_login() - this calls look command by default - session.session_login(player) + session.sessionhandler.login(session, player) class CmdUnconnectedCreate(MuxCommand): """ @@ -224,8 +224,8 @@ class CmdUnconnectedQuit(MuxCommand): def func(self): "Simply close the connection." session = self.caller - session.msg("Good bye! Disconnecting ...") - session.session_disconnect() + #session.msg("Good bye! Disconnecting ...") + session.sessionhandler.disconnect(session, "Good bye! Disconnecting ...") class CmdUnconnectedLook(MuxCommand): """ diff --git a/src/objects/models.py b/src/objects/models.py index 1fa86cd999..e169f55ae3 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -584,7 +584,6 @@ class ObjectDB(TypedObject): if ostring in (_ME, _SELF, '*' + _ME, '*' + _SELF): return self - if use_nicks: nick = None nicktype = "object" @@ -670,7 +669,7 @@ class ObjectDB(TypedObject): break return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, sessid=sessid) - def msg(self, message, from_obj=None, data=None): + def msg(self, msg=None, from_obj=None, data=None, sessid=0): """ Emits something to a session attached to the object. @@ -678,10 +677,14 @@ class ObjectDB(TypedObject): from_obj (obj): object that is sending. data (object): an optional data object that may or may not be used by the protocol. + sessid (int): sessid to relay to, if any. + If set to 0 (default), use self.sessid automatically + If None, echo to all connected sessions """ if _GA(self, 'player'): # note that we must call the player *typeclass'* msg(), otherwise one couldn't overload it. - _GA(_GA(self, 'player'), "typeclass").msg(message, from_obj=from_obj, data=data, sessid=_GA(self, "sessid")) + _GA(_GA(self, 'player'), "typeclass").msg(msg, from_obj=from_obj, data=data, + sessid=(sessid==0 and _GA(self, "sessid") or sessid or None)) def emit_to(self, message, from_obj=None, data=None): "Deprecated. Alias for msg" diff --git a/src/players/models.py b/src/players/models.py index b9465ca6a9..bab020473d 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -423,16 +423,23 @@ class PlayerDB(TypedObject): # a non-character session; this goes to player directly _GA(self, "execute_cmd")(ingoing_string, sessid=sessid) - def disconnect_session_from_player(self, sessid): + def get_session_from_sessid(self, sessid): """ - Access method for disconnecting a given session from the player. + Get the session object from sessid. If session with sessid is not + connected to this player, return None. """ global _SESSIONS if not _SESSIONS: from src.server.sessionhandler import SESSIONS as _SESSIONS - _SESSIONS.disconnect(sessid=sessid) - + return _SESSIONS.sessions_from_player(self, sessid=sessid) + def disconnect_session_from_player(self, sessid): + """ + Access method for disconnecting a given session from the player. + """ + session = self.get_session_from_sessid(sessid) + if session: + session.sessionhandler.disconnect(session) def connect_session_to_character(self, sessid, character, force=False): """ @@ -502,7 +509,6 @@ class PlayerDB(TypedObject): """ char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True) if not char: - print "No reconnecting character found" return self.connect_session_to_character(sessid, char, force=True) diff --git a/src/server/serversession.py b/src/server/serversession.py index b1d358699d..26dbfac127 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -59,23 +59,12 @@ class ServerSession(Session): else: self.player.reconnect_session_to_character(self.sessid) - def session_login(self, player): + def at_login(self, player): """ - Startup mechanisms that need to run at login. This is called - by the login command (which need to have handled authentication - already before calling this method) + Hook called by sessionhandler when the session becomes authenticated. - player - the connected player + player - the player associated with the session """ - - # we have to check this first before uid has been assigned - # this session. - - if not self.sessionhandler.sessions_from_player(player): - player.is_connected = True - - # actually do the login by assigning session data - self.player = player self.user = player.user self.uid = self.user.id @@ -87,31 +76,9 @@ class ServerSession(Session): self.user.last_login = datetime.now() self.user.save() - # player init - player.at_init() - - # Check if this is the first time the *player* logs in - if player.db.FIRST_LOGIN: - player.at_first_login() - del player.db.FIRST_LOGIN - - player.at_pre_login() - - self.log(_('Logged in: %(self)s') % {'self': self}) - - # start (persistent) scripts on this object - #ScriptDB.objects.validate(obj=self.player.character) - - #add session to connected list - self.sessionhandler.login(self) - - player.at_post_login() - - def session_disconnect(self): + def at_disconnect(self): """ - Clean up the session, removing it from the game and doing some - accounting. This method is used also for non-loggedin - accounts. + Hook called by sessionhandler when disconnecting this session. """ if self.logged_in: sessid = self.sessid @@ -123,8 +90,9 @@ class ServerSession(Session): uaccount.save() self.logged_in = False if not self.sessionhandler.sessions_from_player(player): + # no more sessions connected to this player player.is_connected = False - self.sessionhandler.disconnect(self) + def get_player(self): """ @@ -268,12 +236,12 @@ class ServerSession(Session): # easy-access functions - def login(self, player): - "alias for at_login" - self.session_login(player) - def disconnect(self): - "alias for session_disconnect" - self.session_disconnect() + #def login(self, player): + # "alias for at_login" + # self.session_login(player) + #def disconnect(self): + # "alias for session_disconnect" + # self.session_disconnect() def msg(self, string='', data=None): "alias for at_data_out" self.data_out(string, data=data) diff --git a/src/server/sessionhandler.py b/src/server/sessionhandler.py index 73ab503a10..39fef6a80c 100644 --- a/src/server/sessionhandler.py +++ b/src/server/sessionhandler.py @@ -199,6 +199,7 @@ class ServerSessionHandler(SessionHandler): """ session = self.sessions.get(session.sessid, None) if session: + session.at_disconnect() sessid = session.sessid del self.sessions[sessid] # inform portal that session should be closed. @@ -206,7 +207,7 @@ class ServerSessionHandler(SessionHandler): operation=SDISCONN, data=reason) - def login(self, session): + def login(self, session, player): """ Log in the previously unloggedin session and the player we by now should know is connected to it. After this point we @@ -214,15 +215,41 @@ class ServerSessionHandler(SessionHandler): """ # prep the session with player/user info + # we have to check this first before uid has been assigned + # this session. + + if not self.sessions_from_player(player): + player.is_connected = True + + # sets up and assigns all properties on the session + session.at_login(player) + + # player init + player.at_init() + + # Check if this is the first time the *player* logs in + if player.db.FIRST_LOGIN: + player.at_first_login() + del player.db.FIRST_LOGIN + + player.at_pre_login() + + session.log(_('Logged in: %(self)s') % {'self': self}) + + # start (persistent) scripts on this object + #ScriptDB.objects.validate(obj=self.player.character) + if MULTISESSION_MODE == 0: # disconnect all previous sessions. self.disconnect_duplicate_sessions(session) + session.logged_in = True - # sync the portal to this session + # sync the portal to the session sessdata = session.get_sync_data() self.server.amp_protocol.call_remote_PortalAdmin(session.sessid, operation=SLOGIN, data=sessdata) + player.at_post_login() def all_sessions_portal_sync(self): """