Moved login and disconnect from session-level to sessionhandler level to make the process cleaner with hooks rather than direct calls.

This commit is contained in:
Griatch 2013-02-17 18:48:48 +01:00
parent 261363bae7
commit 25505d69a6
7 changed files with 109 additions and 70 deletions

View file

@ -118,14 +118,12 @@ class Command(object):
# used by the help system to group commands in lists. # used by the help system to group commands in lists.
help_category = "general" help_category = "general"
# this normally does not need to be changed. It allows to turn off # This allows to turn off auto-help entry creation for individual commands.
# auto-help entry creation for individual commands.
auto_help = True auto_help = True
# There is also the property 'obj'. This gets set by the system # auto-set (by Evennia on command instantiation) are:
# on the fly to tie this particular command to a certain in-game entity. # obj - which object this command is defined on
# self.obj should NOT be defined here since it will not be overwritten # sessid - which session-id (if any) is responsible for triggering this command
# if it already exists. #
def __init__(self): def __init__(self):
"the lockhandler works the same as for objects." "the lockhandler works the same as for objects."
@ -190,6 +188,29 @@ class Command(object):
""" """
return self.lockhandler.check(srcobj, access_type, default=default) 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 # Common Command hooks
def at_pre_cmd(self): def at_pre_cmd(self):

View file

@ -388,7 +388,11 @@ class CmdQuit(MuxCommand):
Usage: Usage:
@quit @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" key = "@quit"
locks = "cmd:all()" locks = "cmd:all()"
@ -400,10 +404,20 @@ class CmdQuit(MuxCommand):
else: else:
player = self.caller player = self.caller
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.msg("{RQuitting{n. Hope to see you soon again.", sessid=self.sessid)
player.disconnect_session_from_player(self.sessid) player.disconnect_session_from_player(self.sessid)
#for session in self.caller.sessions:
# session.session_disconnect()
class CmdWho(MuxCommand): class CmdWho(MuxCommand):
""" """

View file

@ -97,7 +97,7 @@ class CmdUnconnectedConnect(MuxCommand):
# at_pre_login() # at_pre_login()
# player.at_post_login() - calls look if no character is set # player.at_post_login() - calls look if no character is set
# character.at_post_login() - this calls look command by default # character.at_post_login() - this calls look command by default
session.session_login(player) session.sessionhandler.login(session, player)
class CmdUnconnectedCreate(MuxCommand): class CmdUnconnectedCreate(MuxCommand):
""" """
@ -224,8 +224,8 @@ class CmdUnconnectedQuit(MuxCommand):
def func(self): def func(self):
"Simply close the connection." "Simply close the connection."
session = self.caller session = self.caller
session.msg("Good bye! Disconnecting ...") #session.msg("Good bye! Disconnecting ...")
session.session_disconnect() session.sessionhandler.disconnect(session, "Good bye! Disconnecting ...")
class CmdUnconnectedLook(MuxCommand): class CmdUnconnectedLook(MuxCommand):
""" """

View file

@ -584,7 +584,6 @@ class ObjectDB(TypedObject):
if ostring in (_ME, _SELF, '*' + _ME, '*' + _SELF): if ostring in (_ME, _SELF, '*' + _ME, '*' + _SELF):
return self return self
if use_nicks: if use_nicks:
nick = None nick = None
nicktype = "object" nicktype = "object"
@ -670,7 +669,7 @@ class ObjectDB(TypedObject):
break break
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, sessid=sessid) 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. Emits something to a session attached to the object.
@ -678,10 +677,14 @@ class ObjectDB(TypedObject):
from_obj (obj): object that is sending. from_obj (obj): object that is sending.
data (object): an optional data object that may or may not data (object): an optional data object that may or may not
be used by the protocol. 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'): if _GA(self, 'player'):
# note that we must call the player *typeclass'* msg(), otherwise one couldn't overload it. # 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): def emit_to(self, message, from_obj=None, data=None):
"Deprecated. Alias for msg" "Deprecated. Alias for msg"

View file

@ -423,16 +423,23 @@ class PlayerDB(TypedObject):
# a non-character session; this goes to player directly # a non-character session; this goes to player directly
_GA(self, "execute_cmd")(ingoing_string, sessid=sessid) _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 global _SESSIONS
if not _SESSIONS: if not _SESSIONS:
from src.server.sessionhandler import SESSIONS as _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): 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) char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True)
if not char: if not char:
print "No reconnecting character found"
return return
self.connect_session_to_character(sessid, char, force=True) self.connect_session_to_character(sessid, char, force=True)

View file

@ -59,23 +59,12 @@ class ServerSession(Session):
else: else:
self.player.reconnect_session_to_character(self.sessid) 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 Hook called by sessionhandler when the session becomes authenticated.
by the login command (which need to have handled authentication
already before calling this method)
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.player = player
self.user = player.user self.user = player.user
self.uid = self.user.id self.uid = self.user.id
@ -87,31 +76,9 @@ class ServerSession(Session):
self.user.last_login = datetime.now() self.user.last_login = datetime.now()
self.user.save() self.user.save()
# player init def at_disconnect(self):
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):
""" """
Clean up the session, removing it from the game and doing some Hook called by sessionhandler when disconnecting this session.
accounting. This method is used also for non-loggedin
accounts.
""" """
if self.logged_in: if self.logged_in:
sessid = self.sessid sessid = self.sessid
@ -123,8 +90,9 @@ class ServerSession(Session):
uaccount.save() uaccount.save()
self.logged_in = False self.logged_in = False
if not self.sessionhandler.sessions_from_player(player): if not self.sessionhandler.sessions_from_player(player):
# no more sessions connected to this player
player.is_connected = False player.is_connected = False
self.sessionhandler.disconnect(self)
def get_player(self): def get_player(self):
""" """
@ -268,12 +236,12 @@ class ServerSession(Session):
# easy-access functions # easy-access functions
def login(self, player): #def login(self, player):
"alias for at_login" # "alias for at_login"
self.session_login(player) # self.session_login(player)
def disconnect(self): #def disconnect(self):
"alias for session_disconnect" # "alias for session_disconnect"
self.session_disconnect() # self.session_disconnect()
def msg(self, string='', data=None): def msg(self, string='', data=None):
"alias for at_data_out" "alias for at_data_out"
self.data_out(string, data=data) self.data_out(string, data=data)

View file

@ -199,6 +199,7 @@ class ServerSessionHandler(SessionHandler):
""" """
session = self.sessions.get(session.sessid, None) session = self.sessions.get(session.sessid, None)
if session: if session:
session.at_disconnect()
sessid = session.sessid sessid = session.sessid
del self.sessions[sessid] del self.sessions[sessid]
# inform portal that session should be closed. # inform portal that session should be closed.
@ -206,7 +207,7 @@ class ServerSessionHandler(SessionHandler):
operation=SDISCONN, operation=SDISCONN,
data=reason) data=reason)
def login(self, session): def login(self, session, player):
""" """
Log in the previously unloggedin session and the player we by Log in the previously unloggedin session and the player we by
now should know is connected to it. After this point we 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 # 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: if MULTISESSION_MODE == 0:
# disconnect all previous sessions. # disconnect all previous sessions.
self.disconnect_duplicate_sessions(session) self.disconnect_duplicate_sessions(session)
session.logged_in = True session.logged_in = True
# sync the portal to this session # sync the portal to the session
sessdata = session.get_sync_data() sessdata = session.get_sync_data()
self.server.amp_protocol.call_remote_PortalAdmin(session.sessid, self.server.amp_protocol.call_remote_PortalAdmin(session.sessid,
operation=SLOGIN, operation=SLOGIN,
data=sessdata) data=sessdata)
player.at_post_login()
def all_sessions_portal_sync(self): def all_sessions_portal_sync(self):
""" """