Further development of the reworking of systems using Sessions rather than session id.

This commit is contained in:
Griatch 2015-11-14 20:32:58 +01:00
parent 709f5ff5b3
commit d496606a3c
19 changed files with 166 additions and 209 deletions

View file

@ -148,7 +148,8 @@ class Command(with_metaclass(CommandMeta, object)):
# auto-set (by Evennia on command instantiation) are: # auto-set (by Evennia on command instantiation) are:
# obj - which object this command is defined on # obj - which object this command is defined on
# sessid - which session-id (if any) is responsible for triggering this command # session - which session is responsible for triggering this command. Only set
# if triggered by a player.
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
@ -297,22 +298,18 @@ class Command(with_metaclass(CommandMeta, object)):
return self.lockhandler.check(srcobj, access_type, default=default) return self.lockhandler.check(srcobj, access_type, default=default)
def msg(self, msg="", to_obj=None, from_obj=None, def msg(self, msg="", to_obj=None, from_obj=None,
sessid=None, all_sessions=False, **kwargs): session=None, **kwargs):
""" """
This is a shortcut instad of calling msg() directly on an This is a shortcut instad of calling msg() directly on an
object - it will detect if caller is an Object or a Player and object - it will detect if caller is an Object or a Player and
also appends self.sessid automatically. also appends self.session automatically.
Args: Args:
msg (str, optional): Text string of message to send. msg (str, optional): Text string of message to send.
to_obj (Object, optional): Target object of message. Defaults to self.caller. to_obj (Object, optional): Target object of message. Defaults to self.caller.
from_obj (Object, optional): Source of message. Defaults to to_obj. from_obj (Object, optional): Source of message. Defaults to to_obj.
sessid (int, optional): Supply data only to a unique session (Session, optional): Supply data only to a unique
session id (normally not used - this is only potentially session.
useful if to_obj is a Player object different from
self.caller or self.caller.player).
all_sessions (bool): Default is to send only to the session
connected to the target object
Kwargs: Kwargs:
kwargs (any): These are all passed on to the message mechanism. Common kwargs (any): These are all passed on to the message mechanism. Common
@ -321,26 +318,9 @@ class Command(with_metaclass(CommandMeta, object)):
""" """
from_obj = from_obj or self.caller from_obj = from_obj or self.caller
to_obj = to_obj or from_obj to_obj = to_obj or from_obj
if not sessid: if not session or to_obj == self.caller:
if hasattr(to_obj, "sessid"): session = to_obj.sessions.get()
# this is the case when to_obj is e.g. a Character to_obj.msg(msg, from_obj=from_obj, session=session, **kwargs)
toobj_sessions = to_obj.sessid.get()
# If to_obj has more than one session MULTISESSION_MODE=3
# we need to send to every session.
#(setting it to None, does it)
session_tosend = None
if len(toobj_sessions) == 1:
session_tosend=toobj_sessions[0]
sessid = all_sessions and None or session_tosend
elif to_obj == self.caller:
# this is the case if to_obj is the calling Player
sessid = all_sessions and None or self.sessid
else:
# if to_obj is a different Player, all their sessions
# will be notified unless sessid was given specifically
sessid = None
to_obj.msg(msg, from_obj=from_obj, sessid=sessid, **kwargs)
# Common Command hooks # Common Command hooks

View file

@ -92,7 +92,7 @@ class CmdBoot(MuxCommand):
for session in boot_list: for session in boot_list:
session.msg(feedback) session.msg(feedback)
pobj.disconnect_session_from_player(session.sessid) pobj.disconnect_session_from_player(session)
# regex matching IP addresses with wildcards, eg. 233.122.4.* # regex matching IP addresses with wildcards, eg. 233.122.4.*

View file

@ -1868,9 +1868,7 @@ class CmdExamine(ObjManipCommand):
string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref) string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref)
if hasattr(obj, "aliases") and obj.aliases.all(): if hasattr(obj, "aliases") and obj.aliases.all():
string += "\n{wAliases{n: %s" % (", ".join(utils.make_iter(str(obj.aliases)))) string += "\n{wAliases{n: %s" % (", ".join(utils.make_iter(str(obj.aliases))))
if hasattr(obj, "sessid") and obj.sessid.count(): if hasattr(obj, "sessions") and obj.sessions:
string += "\n{wsession{n: %s" % obj.sessid.get()
elif hasattr(obj, "sessions") and obj.sessions:
string += "\n{wsession(s){n: %s" % (", ".join(str(sess.sessid) string += "\n{wsession(s){n: %s" % (", ".join(str(sess.sessid)
for sess in obj.sessions)) for sess in obj.sessions))
if hasattr(obj, "has_player") and obj.has_player: if hasattr(obj, "has_player") and obj.has_player:
@ -1924,16 +1922,16 @@ class CmdExamine(ObjManipCommand):
# if we merge on the object level. # if we merge on the object level.
if hasattr(obj, "player") and obj.player: if hasattr(obj, "player") and obj.player:
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.cmdset.all()]) all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.cmdset.all()])
if obj.sessid.count(): if obj.sessions.count():
# if there are more sessions than one on objects it's because of multisession mode 3. # if there are more sessions than one on objects it's because of multisession mode 3.
# we only show the first session's cmdset here (it is -in principle- possible that # we only show the first session's cmdset here (it is -in principle- possible that
# different sessions have different cmdsets but for admins who want such madness # different sessions have different cmdsets but for admins who want such madness
# it is better that they overload with their own CmdExamine to handle it). # it is better that they overload with their own CmdExamine to handle it).
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.get_session(obj.sessid.get()[0]).cmdset.all()]) all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.sessions.all()[0].cmdset.all()])
else: else:
try: try:
# we have to protect this since many objects don't have sessions. # we have to protect this since many objects don't have sessions.
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.get_session(obj.sessid.get()).cmdset.all()]) all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.get_session(obj.sessions.get()).cmdset.all()])
except (TypeError, AttributeError): except (TypeError, AttributeError):
pass pass
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()] all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
@ -2043,7 +2041,7 @@ class CmdExamine(ObjManipCommand):
# we are only interested in specific attributes # we are only interested in specific attributes
caller.msg(self.format_attributes(obj, attrname, crop=False)) caller.msg(self.format_attributes(obj, attrname, crop=False))
else: else:
if hasattr(obj, "sessid") and obj.sessid.count(): if obj.sessions.count():
mergemode = "session" mergemode = "session"
elif self.player_mode: elif self.player_mode:
mergemode = "player" mergemode = "player"

View file

@ -188,6 +188,6 @@ class MuxPlayerCommand(MuxCommand):
self.caller = self.caller.player self.caller = self.caller.player
elif utils.inherits_from(self.caller, "evennia.players.players.DefaultPlayer"): elif utils.inherits_from(self.caller, "evennia.players.players.DefaultPlayer"):
# caller was already a Player # caller was already a Player
self.character = self.caller.get_puppet(self.sessid) self.character = self.caller.get_puppet(self.session)
else: else:
self.character = None self.character = None

View file

@ -101,7 +101,7 @@ class CmdOOCLook(MuxPlayerLookCommand):
return return
# call on-player look helper method # call on-player look helper method
self.msg(self.player.at_look(target=self.playable, sessid=self.sessid)) self.msg(self.player.at_look(target=self.playable, session=self.session))
class CmdCharCreate(MuxPlayerCommand): class CmdCharCreate(MuxPlayerCommand):
@ -188,7 +188,7 @@ class CmdIC(MuxPlayerCommand):
Main puppet method Main puppet method
""" """
player = self.player player = self.player
sessid = self.sessid session = self.session
new_character = None new_character = None
if not self.args: if not self.args:
@ -205,7 +205,7 @@ class CmdIC(MuxPlayerCommand):
self.msg("That is not a valid character choice.") self.msg("That is not a valid character choice.")
return return
try: try:
player.puppet_object(sessid, new_character) player.puppet_object(session, new_character)
player.db._last_puppet = new_character player.db._last_puppet = new_character
except RuntimeError as exc: except RuntimeError as exc:
self.msg("{rYou cannot become {C%s{n: %s" % (new_character.name, exc)) self.msg("{rYou cannot become {C%s{n: %s" % (new_character.name, exc))
@ -234,9 +234,9 @@ class CmdOOC(MuxPlayerLookCommand):
"Implement function" "Implement function"
player = self.player player = self.player
sessid = self.sessid session = self.session
old_char = player.get_puppet(sessid) old_char = player.get_puppet(session)
if not old_char: if not old_char:
string = "You are already OOC." string = "You are already OOC."
self.msg(string) self.msg(string)
@ -246,7 +246,7 @@ class CmdOOC(MuxPlayerLookCommand):
# disconnect # disconnect
try: try:
player.unpuppet_object(sessid) player.unpuppet_object(session)
self.msg("\n{GYou go OOC.{n\n") self.msg("\n{GYou go OOC.{n\n")
if _MULTISESSION_MODE < 2: if _MULTISESSION_MODE < 2:
@ -254,7 +254,7 @@ class CmdOOC(MuxPlayerLookCommand):
self.msg("You are out-of-character (OOC).\nUse {w@ic{n to get back into the game.") self.msg("You are out-of-character (OOC).\nUse {w@ic{n to get back into the game.")
return return
self.msg(player.at_look(target=self.playable, sessid=sessid)) self.msg(player.at_look(target=self.playable, session=session))
except RuntimeError as exc: except RuntimeError as exc:
self.msg("{rCould not unpuppet from {c%s{n: %s" % (old_char, exc)) self.msg("{rCould not unpuppet from {c%s{n: %s" % (old_char, exc))
@ -480,19 +480,19 @@ class CmdQuit(MuxPlayerCommand):
player = self.player player = self.player
if 'all' in self.switches: if 'all' in self.switches:
player.msg("{RQuitting{n all sessions. Hope to see you soon again.", sessid=self.sessid) player.msg("{RQuitting{n all sessions. Hope to see you soon again.", session=self.session)
for session in player.get_all_sessions(): for session in player.sessions.all()
player.disconnect_session_from_player(session.sessid) player.disconnect_session_from_player(session)
else: else:
nsess = len(player.get_all_sessions()) nsess = len(player.sessions.all())
if nsess == 2: if nsess == 2:
player.msg("{RQuitting{n. One session is still connected.", sessid=self.sessid) player.msg("{RQuitting{n. One session is still connected.", session=self.session)
elif nsess > 2: elif nsess > 2:
player.msg("{RQuitting{n. %i session are still connected." % (nsess-1), sessid=self.sessid) player.msg("{RQuitting{n. %i session are still connected." % (nsess-1), session=self.session)
else: else:
# we are quitting the last available session # we are quitting the last available session
player.msg("{RQuitting{n. Hope to see you again, soon.", sessid=self.sessid) player.msg("{RQuitting{n. Hope to see you again, soon.", session=self.session)
player.disconnect_session_from_player(self.sessid) player.disconnect_session_from_player(self.session)
@ -601,8 +601,8 @@ class CmdQuell(MuxPlayerCommand):
def _recache_locks(self, player): def _recache_locks(self, player):
"Helper method to reset the lockhandler on an already puppeted object" "Helper method to reset the lockhandler on an already puppeted object"
if self.sessid: if self.session:
char = player.get_puppet(self.sessid) char = session.puppet
if char: if char:
# we are already puppeting an object. We need to reset # we are already puppeting an object. We need to reset
# the lock caches (otherwise the superuser status change # the lock caches (otherwise the superuser status change
@ -625,7 +625,7 @@ class CmdQuell(MuxPlayerCommand):
self.msg("Already quelling Player%s permissions." % permstr) self.msg("Already quelling Player%s permissions." % permstr)
return return
player.attributes.add('_quell', True) player.attributes.add('_quell', True)
puppet = player.get_puppet(self.sessid) puppet = self.session.puppet
if puppet: if puppet:
cpermstr = " (%s)" % ", ".join(puppet.permissions.all()) cpermstr = " (%s)" % ", ".join(puppet.permissions.all())
cpermstr = "Quelling to current puppet's permissions%s." % cpermstr cpermstr = "Quelling to current puppet's permissions%s." % cpermstr

View file

@ -178,7 +178,7 @@ class CmdPy(MuxCommand):
'inherits_from': utils.inherits_from} 'inherits_from': utils.inherits_from}
try: try:
self.msg(">>> %s" % pycode, raw=True, sessid=self.sessid) self.msg(">>> %s" % pycode, raw=True, session=self.session)
except TypeError: except TypeError:
self.msg(">>> %s" % pycode, raw=True) self.msg(">>> %s" % pycode, raw=True)
@ -209,7 +209,7 @@ class CmdPy(MuxCommand):
ret = "\n".join("<<< %s" % line for line in errlist if line) ret = "\n".join("<<< %s" % line for line in errlist if line)
try: try:
self.msg(ret, sessid=self.sessid, raw=True) self.msg(ret, session=self.session, raw=True)
except TypeError: except TypeError:
self.msg(ret, raw=True) self.msg(ret, raw=True)

View file

@ -55,7 +55,6 @@ class CommandTest(EvenniaTest):
cmdobj.cmdstring = cmdobj.key cmdobj.cmdstring = cmdobj.key
cmdobj.args = args cmdobj.args = args
cmdobj.cmdset = cmdset cmdobj.cmdset = cmdset
cmdobj.sessid = 1
cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.session = SESSIONS.session_from_sessid(1)
cmdobj.player = self.player cmdobj.player = self.player
cmdobj.raw_string = cmdobj.key + " " + args cmdobj.raw_string = cmdobj.key + " " + args
@ -174,7 +173,7 @@ class TestPlayer(CommandTest):
self.call(player.CmdOOC(), "", "You go OOC.", caller=self.player) self.call(player.CmdOOC(), "", "You go OOC.", caller=self.player)
def test_ic(self): def test_ic(self):
self.player.unpuppet_object(self.session.sessid) self.player.unpuppet_object(self.session)
self.call(player.CmdIC(), "Char", "You become Char.", caller=self.player, receiver=self.char1) self.call(player.CmdIC(), "Char", "You become Char.", caller=self.player, receiver=self.char1)
def test_password(self): def test_password(self):

View file

@ -237,7 +237,7 @@ class CmdUnconnectedConnect(MuxCommand):
# player.at_init() # always called when object is loaded from disk # player.at_init() # always called when object is loaded from disk
# player.at_first_login() # only once, for player-centric setup # player.at_first_login() # only once, for player-centric setup
# player.at_pre_login() # player.at_pre_login()
# player.at_post_login(sessid=sessid) # player.at_post_login(session=session)
session.sessionhandler.login(session, player) session.sessionhandler.login(session, player)

View file

@ -110,7 +110,7 @@ class GenderCharacter(DefaultCharacter):
pronoun = _GENDER_PRONOUN_MAP[gender][typ.lower()] pronoun = _GENDER_PRONOUN_MAP[gender][typ.lower()]
return pronoun.capitalize() if typ.isupper() else pronoun return pronoun.capitalize() if typ.isupper() else pronoun
def msg(self, text, from_obj=None, sessid=0, **kwargs): def msg(self, text, from_obj=None, session=None, **kwargs):
""" """
Emits something to a session attached to the object. Emits something to a session attached to the object.
Overloads the default msg() implementation to include Overloads the default msg() implementation to include
@ -120,8 +120,8 @@ class GenderCharacter(DefaultCharacter):
text (str, optional): The message to send text (str, optional): The message to send
from_obj (obj, optional): object that is sending. If from_obj (obj, optional): object that is sending. If
given, at_msg_send will be called given, at_msg_send will be called
sessid (int or list, optional): sessid or list of session (Session or list, optional): session or list of
sessids to relay to, if any. If set, will sessions to relay to, if any. If set, will
force send regardless of MULTISESSION_MODE. force send regardless of MULTISESSION_MODE.
Notes: Notes:
`at_msg_receive` will be called on this Object. `at_msg_receive` will be called on this Object.
@ -130,4 +130,4 @@ class GenderCharacter(DefaultCharacter):
""" """
# pre-process the text before continuing # pre-process the text before continuing
text = _RE_GENDER_PRONOUN.sub(self._get_pronoun, text) text = _RE_GENDER_PRONOUN.sub(self._get_pronoun, text)
super(GenderCharacter, self).msg(text, from_obj=from_obj, sessid=sessid, **kwargs) super(GenderCharacter, self).msg(text, from_obj=from_obj, session=session, **kwargs)

View file

@ -43,7 +43,8 @@ class Object(DefaultObject):
player (Player) - controlling player (if any, only set together with player (Player) - controlling player (if any, only set together with
sessid below) sessid below)
sessid (int, read-only) - session id (if any, only set together with sessid (int, read-only) - session id (if any, only set together with
player above) player above). Use `sessions` handler to get the
Sessions directly.
location (Object) - current location. Is None if this is a room location (Object) - current location. Is None if this is a room
home (Object) - safety start-location home (Object) - safety start-location
sessions (list of Sessions, read-only) - returns all sessions connected sessions (list of Sessions, read-only) - returns all sessions connected
@ -66,6 +67,8 @@ class Object(DefaultObject):
scripts - script-handler. Add new scripts to object with scripts.add() scripts - script-handler. Add new scripts to object with scripts.add()
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
nicks - nick-handler. New nicks with nicks.add(). nicks - nick-handler. New nicks with nicks.add().
sessions - sessions-handler. Get Sessions connected to this
object with sessions.get()
* Helper methods (see src.objects.objects.py for full headers) * Helper methods (see src.objects.objects.py for full headers)

View file

@ -65,7 +65,7 @@ class Player(DefaultPlayer):
msg(text=None, **kwargs) msg(text=None, **kwargs)
swap_character(new_character, delete_old_character=False) swap_character(new_character, delete_old_character=False)
execute_cmd(raw_string, sessid=None) execute_cmd(raw_string, session=None)
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False) search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
is_typeclass(typeclass, exact=False) is_typeclass(typeclass, exact=False)
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
@ -83,7 +83,7 @@ class Player(DefaultPlayer):
at_init() at_init()
at_cmdset_get(**kwargs) at_cmdset_get(**kwargs)
at_first_login() at_first_login()
at_post_login(sessid=None) at_post_login(session=None)
at_disconnect() at_disconnect()
at_message_receive() at_message_receive()
at_message_send() at_message_send()

View file

@ -90,7 +90,7 @@ class CmdBotListen(Command):
key = "bot_data_in" key = "bot_data_in"
def func(self): def func(self):
"Relay to typeclass" "Relay to typeclass"
self.obj.execute_cmd(self.args.strip(), sessid=self.sessid) self.obj.execute_cmd(self.args.strip(), session=self.session)
class BotCmdSet(CmdSet): class BotCmdSet(CmdSet):
""" """
@ -135,19 +135,19 @@ class Bot(DefaultPlayer):
""" """
pass pass
def msg(self, text=None, from_obj=None, sessid=None, **kwargs): def msg(self, text=None, from_obj=None, session=None, **kwargs):
""" """
Evennia -> outgoing protocol Evennia -> outgoing protocol
""" """
super(Bot, self).msg(text=text, from_obj=from_obj, sessid=sessid, **kwargs) super(Bot, self).msg(text=text, from_obj=from_obj, session=session, **kwargs)
def execute_cmd(self, raw_string, sessid=None): def execute_cmd(self, raw_string, session=None):
""" """
Incoming protocol -> Evennia Incoming protocol -> Evennia
""" """
super(Bot, self).msg(raw_string, sessid=sessid) super(Bot, self).msg(raw_string, session=session)
def at_server_shutdown(self): def at_server_shutdown(self):
""" """
@ -236,14 +236,14 @@ class IRCBot(Bot):
text = "bot_data_out %s" % text text = "bot_data_out %s" % text
super(IRCBot, self).msg(text=text) super(IRCBot, self).msg(text=text)
def execute_cmd(self, text=None, sessid=None): def execute_cmd(self, text=None, session=None):
""" """
Take incoming data and send it to connected channel. This is Take incoming data and send it to connected channel. This is
triggered by the CmdListen command in the BotCmdSet. triggered by the CmdListen command in the BotCmdSet.
Args: Args:
text (str, optional): Command string. text (str, optional): Command string.
sessid (int, optional): Session id responsible for this session (Session, optional): Session responsible for this
command. command.
""" """
@ -296,7 +296,7 @@ class RSSBot(Bot):
"rate": self.db.rss_rate} "rate": self.db.rss_rate}
_SESSIONS.start_bot_session("evennia.server.portal.rss.RSSBotFactory", configdict) _SESSIONS.start_bot_session("evennia.server.portal.rss.RSSBotFactory", configdict)
def execute_cmd(self, text=None, sessid=None): def execute_cmd(self, text=None, session=None):
""" """
Echo RSS input to connected channel Echo RSS input to connected channel
@ -386,13 +386,13 @@ class IMC2Bot(Bot):
text = "bot_data_out %s" % text text = "bot_data_out %s" % text
self.msg(text=text) self.msg(text=text)
def execute_cmd(self, text=None, sessid=None): def execute_cmd(self, text=None, session=None):
""" """
Relay incoming data to connected channel. Relay incoming data to connected channel.
Args: Args:
text (str, optional): Command string. text (str, optional): Command string.
sessid (int, optional): Session id responsible for this session (Session, optional): Session responsible for this
command. command.
""" """

View file

@ -430,8 +430,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
raw_string = self.nicks.nickreplace(raw_string, raw_string = self.nicks.nickreplace(raw_string,
categories=("inputline", "channel"), include_player=False) categories=("inputline", "channel"), include_player=False)
if not session and _MULTISESSION_MODE in (0, 1): if not session and _MULTISESSION_MODE in (0, 1):
# for these modes we use the # for these modes we use the first/only session
session sessions = self.sessions.get()
session = sessions[0] if sessions else None
return cmdhandler.cmdhandler(self, raw_string, return cmdhandler.cmdhandler(self, raw_string,
callertype="player", session=session, **kwargs) callertype="player", session=session, **kwargs)
@ -679,7 +680,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
the player loose. the player loose.
Args: Args:
sessid (int, optional): Session logging in, if any. session (Session, optional): Session logging in, if any.
Notes: Notes:
This is called *before* an eventual Character's This is called *before* an eventual Character's
@ -786,7 +787,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
# list of targets - make list # list of targets - make list
characters = target characters = target
sessions = self.get_all_sessions() sessions = self.sessions.all()
is_su = self.is_superuser is_su = self.is_superuser
# text shown when looking in the ooc area # text shown when looking in the ooc area
@ -845,7 +846,7 @@ class DefaultGuest(DefaultPlayer):
MULTISESSION_MODE we're in. They don't get a choice. MULTISESSION_MODE we're in. They don't get a choice.
Args: Args:
sessid (int, optional): Id of Session connecting. session (Session, optional): Session connecting.
""" """
self._send_to_connect_channel("{G%s connected{n" % self.key) self._send_to_connect_channel("{G%s connected{n" % self.key)

View file

@ -18,7 +18,7 @@ Server - (AMP server) Handles all mud operations. The server holds its own list
from __future__ import print_function from __future__ import print_function
# imports needed on both server and portal side # imports needed on both server and portal side
import os, sys import os
from time import time from time import time
from collections import defaultdict from collections import defaultdict
from itertools import count from itertools import count
@ -28,7 +28,7 @@ try:
except ImportError: except ImportError:
import pickle import pickle
from twisted.protocols import amp from twisted.protocols import amp
from twisted.internet import protocol, reactor from twisted.internet import protocol
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
from evennia.utils import logger from evennia.utils import logger
from evennia.utils.utils import to_str, variable_from_module from evennia.utils.utils import to_str, variable_from_module
@ -416,10 +416,10 @@ class AMPProtocol(amp.AMP):
""" """
sessid, kwargs = loads(packed_data) sessid, kwargs = loads(packed_data)
self.factory.server.sessions.data_in(sessid, **kwargs) self.factory.server.sessions.data_in(self.factory.server.sessions[sessid], **kwargs)
return {} return {}
def send_MsgPortal2Server(self, sessid, text="", **kwargs): def send_MsgPortal2Server(self, session, text="", **kwargs):
""" """
Access method called by the Portal and executed on the Portal. Access method called by the Portal and executed on the Portal.
@ -432,7 +432,7 @@ class AMPProtocol(amp.AMP):
deferred (Deferred): Asynchronous return. deferred (Deferred): Asynchronous return.
""" """
return self.send_data(MsgPortal2Server, sessid, text=text, **kwargs) return self.send_data(MsgPortal2Server, session.sessid, text=text, **kwargs)
# Server -> Portal message # Server -> Portal message
@ -442,31 +442,26 @@ class AMPProtocol(amp.AMP):
Receives message arriving to Portal from Server. Receives message arriving to Portal from Server.
This method is executed on the Portal. This method is executed on the Portal.
Since AMP has a limit of 65355 bytes per message, it's
possible the data comes in multiple chunks; if so (nparts>1)
we buffer the data and wait for the remaining parts to arrive
before continuing.
Args: Args:
packed_data (str): Pickled data (sessid, kwargs) coming over the wire. packed_data (str): Pickled data (sessid, kwargs) coming over the wire.
""" """
sessid, kwargs = loads(packed_data) sessid, kwargs = loads(packed_data)
self.factory.portal.sessions.data_out(sessid, **kwargs) self.factory.portal.sessions.data_out(self.factory.portal.sessions[sessid], **kwargs)
return {} return {}
def send_MsgServer2Portal(self, sessid, text="", **kwargs): def send_MsgServer2Portal(self, session, text="", **kwargs):
""" """
Access method - executed on the Server for sending data Access method - executed on the Server for sending data
to Portal. to Portal.
Args: Args:
sessid (int): Unique Session id. session (Session): Unique Session.
msg (str, optional): Message to send over the wire. msg (str, optional): Message to send over the wire.
kwargs (any, optiona): Extra data. kwargs (any, optiona): Extra data.
""" """
return self.send_data(MsgServer2Portal, sessid, text=text, **kwargs) return self.send_data(MsgServer2Portal, session.sessid, text=text, **kwargs)
# Server administration from the Portal side # Server administration from the Portal side
@AdminPortal2Server.responder @AdminPortal2Server.responder
@ -483,7 +478,7 @@ class AMPProtocol(amp.AMP):
sessid, kwargs = loads(packed_data) sessid, kwargs = loads(packed_data)
operation = kwargs.pop("operation", "") operation = kwargs.pop("operation", "")
server_sessionhandler = self.factory.server.sessions server_sessionhandler = self.factory.server.sessions
session = server_sessionhandler[sessid]
if operation == PCONN: # portal_session_connect if operation == PCONN: # portal_session_connect
# create a new session and sync it # create a new session and sync it
@ -494,7 +489,7 @@ class AMPProtocol(amp.AMP):
elif operation == PDISCONN: # portal_session_disconnect elif operation == PDISCONN: # portal_session_disconnect
# session closed from portal side # session closed from portal side
self.factory.server.sessions.portal_disconnect(sessid) self.factory.server.sessions.portal_disconnect(session)
elif operation == PSYNC: # portal_session_sync elif operation == PSYNC: # portal_session_sync
# force a resync of sessions when portal reconnects to # force a resync of sessions when portal reconnects to
@ -507,20 +502,20 @@ class AMPProtocol(amp.AMP):
raise Exception("operation %(op)s not recognized." % {'op': operation}) raise Exception("operation %(op)s not recognized." % {'op': operation})
return {} return {}
def send_AdminPortal2Server(self, sessid, operation="", **kwargs): def send_AdminPortal2Server(self, session, operation="", **kwargs):
""" """
Send Admin instructions from the Portal to the Server. Send Admin instructions from the Portal to the Server.
Executed Executed
on the Portal. on the Portal.
Args: Args:
sessid (int): Session id. session (Session): Session.
operation (char, optional): Identifier for the server operation, as defined by the operation (char, optional): Identifier for the server operation, as defined by the
global variables in `evennia/server/amp.py`. global variables in `evennia/server/amp.py`.
data (str or dict, optional): Data used in the administrative operation. data (str or dict, optional): Data used in the administrative operation.
""" """
return self.send_data(AdminPortal2Server, sessid, operation=operation, **kwargs) return self.send_data(AdminPortal2Server, session.sessid, operation=operation, **kwargs)
# Portal administraton from the Server side # Portal administraton from the Server side
@ -539,13 +534,15 @@ class AMPProtocol(amp.AMP):
operation = kwargs.pop("operation") operation = kwargs.pop("operation")
portal_sessionhandler = self.factory.portal.sessions portal_sessionhandler = self.factory.portal.sessions
session = portal_sessionhandler[sessid]
if operation == SLOGIN: # server_session_login if operation == SLOGIN: # server_session_login
# a session has authenticated; sync it. # a session has authenticated; sync it.
portal_sessionhandler.server_logged_in(sessid, kwargs.get("sessiondata")) portal_sessionhandler.server_logged_in(session, kwargs.get("sessiondata"))
elif operation == SDISCONN: # server_session_disconnect elif operation == SDISCONN: # server_session_disconnect
# the server is ordering to disconnect the session # the server is ordering to disconnect the session
portal_sessionhandler.server_disconnect(sessid, reason=kwargs.get("reason")) portal_sessionhandler.server_disconnect(session, reason=kwargs.get("reason"))
elif operation == SDISCONNALL: # server_session_disconnect_all elif operation == SDISCONNALL: # server_session_disconnect_all
# server orders all sessions to disconnect # server orders all sessions to disconnect
@ -569,20 +566,20 @@ class AMPProtocol(amp.AMP):
raise Exception("operation %(op)s not recognized." % {'op': operation}) raise Exception("operation %(op)s not recognized." % {'op': operation})
return {} return {}
def send_AdminServer2Portal(self, sessid, operation="", **kwargs): def send_AdminServer2Portal(self, session, operation="", **kwargs):
""" """
Administrative access method called by the Server to send an Administrative access method called by the Server to send an
instruction to the Portal. instruction to the Portal.
Args: Args:
sessid (int): Session id. session (Session): Session.
operation (char, optional): Identifier for the server operation (char, optional): Identifier for the server
operation, as defined by the global variables in operation, as defined by the global variables in
`evennia/server/amp.py`. `evennia/server/amp.py`.
data (str or dict, optional): Data going into the adminstrative. data (str or dict, optional): Data going into the adminstrative.
""" """
return self.send_data(AdminServer2Portal, sessid, operation=operation, **kwargs) return self.send_data(AdminServer2Portal, session.sessid, operation=operation, **kwargs)
# Extra functions # Extra functions

View file

@ -125,7 +125,7 @@ def oob_repeat(session, oobfuncname, interval, *args, **kwargs):
interval = 20 if not interval else (max(5, interval)) interval = 20 if not interval else (max(5, interval))
obj = session.get_puppet_or_player() obj = session.get_puppet_or_player()
if obj and oobfuncname != "REPEAT": if obj and oobfuncname != "REPEAT":
OOB_HANDLER.add_repeater(obj, session.sessid, oobfuncname, interval, *args, **kwargs) OOB_HANDLER.add_repeater(obj, session, oobfuncname, interval, *args, **kwargs)
##OOB{"UNREPEAT":10} ##OOB{"UNREPEAT":10}
@ -146,7 +146,7 @@ def oob_unrepeat(session, oobfuncname, interval):
""" """
obj = session.get_puppet_or_player() obj = session.get_puppet_or_player()
if obj: if obj:
OOB_HANDLER.remove_repeater(obj, session.sessid, oobfuncname, interval) OOB_HANDLER.remove_repeater(obj, session, oobfuncname, interval)
# #
@ -251,10 +251,10 @@ def oob_report(session, *args, **kwargs):
oob_error(session, "No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) oob_error(session, "No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname)
# the field_monitors require an oob function as a callback when they report a change. # the field_monitors require an oob function as a callback when they report a change.
elif propname.startswith("db_"): elif propname.startswith("db_"):
OOB_HANDLER.add_field_monitor(obj, session.sessid, propname, "return_field_report") OOB_HANDLER.add_field_monitor(obj, session, propname, "return_field_report")
ret.append(to_str(_GA(obj, propname), force_string=True)) ret.append(to_str(_GA(obj, propname), force_string=True))
else: else:
OOB_HANDLER.add_attribute_monitor(obj, session.sessid, propname, "return_attribute_report") OOB_HANDLER.add_attribute_monitor(obj, session, propname, "return_attribute_report")
ret.append(_GA(obj, "db_value")) ret.append(_GA(obj, "db_value"))
session.msg(oob=("MSDP_ARRAY", ret)) session.msg(oob=("MSDP_ARRAY", ret))
else: else:
@ -313,9 +313,9 @@ def oob_unreport(session, *args, **kwargs):
if not propname: if not propname:
oob_error(session, "No Un-Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) oob_error(session, "No Un-Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname)
elif propname.startswith("db_"): elif propname.startswith("db_"):
OOB_HANDLER.remove_field_monitor(obj, session.sessid, propname, "oob_return_field_report") OOB_HANDLER.remove_field_monitor(obj, session, propname, "oob_return_field_report")
else: # assume attribute else: # assume attribute
OOB_HANDLER.remove_attribute_monitor(obj, session.sessid, propname, "oob_return_attribute_report") OOB_HANDLER.remove_attribute_monitor(obj, session, propname, "oob_return_attribute_report")
else: else:
oob_error(session, "You must log in first.") oob_error(session, "You must log in first.")
@ -358,7 +358,7 @@ def oob_list(session, mode, *args, **kwargs):
# we need to check so as to use the right return value depending on if it is # we need to check so as to use the right return value depending on if it is
# an Attribute (identified by tracking the db_value field) or a normal database field # an Attribute (identified by tracking the db_value field) or a normal database field
# reported is a list of tuples (obj, propname, args, kwargs) # reported is a list of tuples (obj, propname, args, kwargs)
reported = OOB_HANDLER.get_all_monitors(session.sessid) reported = OOB_HANDLER.get_all_monitors(session)
reported = [rep[0].key if rep[1] == "db_value" else rep[1] for rep in reported] reported = [rep[0].key if rep[1] == "db_value" else rep[1] for rep in reported]
session.msg(oob=("REPORTED_VARIABLES", reported)) session.msg(oob=("REPORTED_VARIABLES", reported))
elif mode == "SENDABLE_VARIABLES": elif mode == "SENDABLE_VARIABLES":

View file

@ -70,15 +70,17 @@ class OOBFieldMonitor(object):
# oobtuples is a list [(oobfuncname, args, kwargs), ...], # oobtuples is a list [(oobfuncname, args, kwargs), ...],
# a potential list of oob commands to call when this # a potential list of oob commands to call when this
# field changes. # field changes.
for (oobfuncname, args, kwargs) in oobtuples: sessid = SESSIONS.get(sessid)
OOB_HANDLER.execute_cmd(sessid, oobfuncname, fieldname, self.obj, *args, **kwargs) if sessid:
for (oobfuncname, args, kwargs) in oobtuples:
OOB_HANDLER.execute_cmd(sessid, oobfuncname, fieldname, self.obj, *args, **kwargs)
def add(self, sessid, oobfuncname, *args, **kwargs): def add(self, session, oobfuncname, *args, **kwargs):
""" """
Add a specific tracking callback to monitor Add a specific tracking callback to monitor
Args: Args:
sessid (int): Session id session (int): Session.
oobfuncname (str): oob command to call when field updates oobfuncname (str): oob command to call when field updates
args,kwargs (any): arguments to pass to oob commjand args,kwargs (any): arguments to pass to oob commjand
@ -88,9 +90,9 @@ class OOBFieldMonitor(object):
field updates. field updates.
""" """
self.subscribers[sessid].append((oobfuncname, args, kwargs)) self.subscribers[session.sessid].append((oobfuncname, args, kwargs))
def remove(self, sessid, oobfuncname=None): def remove(self, session, oobfuncname=None):
""" """
Remove a subscribing session from the monitor Remove a subscribing session from the monitor
@ -101,10 +103,10 @@ class OOBFieldMonitor(object):
""" """
if oobfuncname: if oobfuncname:
self.subscribers[sessid] = [item for item in self.subscribers[sessid] self.subscribers[session.sessid] = [item for item in self.subscribers[session.sessid]
if item[0] != oobfuncname] if item[0] != oobfuncname]
else: else:
self.subscribers.pop(sessid, None) self.subscribers.pop(session.sessid, None)
class OOBAtRepeater(object): class OOBAtRepeater(object):
@ -268,22 +270,20 @@ class OOBHandler(TickerHandler):
oobfuncname = kwargs["_oobfuncname"] oobfuncname = kwargs["_oobfuncname"]
self.add_repeater(obj, sessid, oobfuncname, interval, *args, **kwargs) self.add_repeater(obj, sessid, oobfuncname, interval, *args, **kwargs)
def add_repeater(self, obj, sessid, oobfuncname, interval=20, *args, **kwargs): def add_repeater(self, obj, session, oobfuncname, interval=20, *args, **kwargs):
""" """
Set an oob function to be repeatedly called. Set an oob function to be repeatedly called.
Args: Args:
obj (Object) - the object on which to register the repeat obj (Object); The object on which to register the repeat.
sessid (int) - session id of the session registering session (Session): Session of the session registering.
oobfuncname (str) - oob function name to call every interval seconds oobfuncname (str): Oob function name to call every interval seconds.
interval (int, optional) - interval to call oobfunc, in seconds interval (int, optional): Interval to call oobfunc, in seconds.
Notes: Notes:
*args, **kwargs are used as extra arguments to the oobfunc. *args, **kwargs are used as extra arguments to the oobfunc.
""" """
# check so we didn't get a session instead of a sessid sessid = session
if not isinstance(sessid, int):
sessid = sessid.sessid
hook = OOBAtRepeater() hook = OOBAtRepeater()
hookname = self._get_repeater_hook_name(oobfuncname, interval, sessid) hookname = self._get_repeater_hook_name(oobfuncname, interval, sessid)
_SA(obj, hookname, hook) _SA(obj, hookname, hook)
@ -291,20 +291,18 @@ class OOBHandler(TickerHandler):
kwargs.update({"_sessid":sessid, "_oobfuncname":oobfuncname}) kwargs.update({"_sessid":sessid, "_oobfuncname":oobfuncname})
super(OOBHandler, self).add(obj, int(interval), oobfuncname, hookname, *args, **kwargs) super(OOBHandler, self).add(obj, int(interval), oobfuncname, hookname, *args, **kwargs)
def remove_repeater(self, obj, sessid, oobfuncname, interval=20): def remove_repeater(self, obj, session, oobfuncname, interval=20):
""" """
Remove the repeatedly calling oob function Remove the repeatedly calling oob function
Args: Args:
obj (Object): The object on which the repeater sits obj (Object): The object on which the repeater sits
sessid (int): Session id of the Session that registered the repeater sessid (Session): Session that registered the repeater
oobfuncname (str): Name of oob function to call at repeat oobfuncname (str): Name of oob function to call at repeat
interval (int, optional): Number of seconds between repeats interval (int, optional): Number of seconds between repeats
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
super(OOBHandler, self).remove(obj, interval, idstring=oobfuncname) super(OOBHandler, self).remove(obj, interval, idstring=oobfuncname)
hookname = self._get_repeater_hook_name(oobfuncname, interval, sessid) hookname = self._get_repeater_hook_name(oobfuncname, interval, sessid)
try: try:
@ -312,16 +310,16 @@ class OOBHandler(TickerHandler):
except AttributeError: except AttributeError:
pass pass
def add_field_monitor(self, obj, sessid, field_name, oobfuncname, *args, **kwargs): def add_field_monitor(self, obj, session, field_name, oobfuncname, *args, **kwargs):
""" """
Add a monitor tracking a database field Add a monitor tracking a database field
Args: Args:
obj (Object): The object who'se field is to be monitored obj (Object): The object who'se field is to be monitored.
sessid (int): Session if of the session monitoring session (Session): Session monitoring.
field_name (str): Name of database field to monitor. The db_* can optionally field_name (str): Name of database field to monitor. The db_* can optionally
be skipped (it will be automatically appended if missing) be skipped (it will be automatically appended if missing).
oobfuncname (str): OOB function to call when field changes oobfuncname (str): OOB function to call when field changes.
Notes: Notes:
When the field updates the given oobfunction will be called as When the field updates the given oobfunction will be called as
@ -333,23 +331,21 @@ class OOBHandler(TickerHandler):
can also easily get the new field value if you want. can also easily get the new field value if you want.
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
# all database field names starts with db_* # all database field names starts with db_*
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
self._add_monitor(obj, sessid, field_name, oobfuncname, *args, **kwargs) self._add_monitor(obj, sessid, field_name, oobfuncname, *args, **kwargs)
def remove_field_monitor(self, obj, sessid, field_name, oobfuncname=None): def remove_field_monitor(self, obj, session, field_name, oobfuncname=None):
""" """
Un-tracks a database field Un-tracks a database field
Args: Args:
obj (Object): Entity with the monitored field obj (Object): Entity with the monitored field.
sessid (int): Session id of session that monitors session (Session): Session that monitors.
field_name (str): database field monitored (the db_* can optionally be field_name (str): database field monitored (the db_* can optionally be
skipped (it will be auto-appended if missing) skipped (it will be auto-appended if missing).
oobfuncname (str, optional): OOB command to call on that field oobfuncname (str, optional): OOB command to call on that field.
Notes: Notes:
When the Attributes db_value updates the given oobfunction When the Attributes db_value updates the given oobfunction
@ -361,65 +357,57 @@ class OOBHandler(TickerHandler):
`obj` is the object on which the field sits. From this you `obj` is the object on which the field sits. From this you
can also easily get the new field value if you want. can also easily get the new field value if you want.
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
self._remove_monitor(obj, sessid, field_name, oobfuncname=oobfuncname) self._remove_monitor(obj, sessid, field_name, oobfuncname=oobfuncname)
def add_attribute_monitor(self, obj, sessid, attr_name, oobfuncname, *args, **kwargs): def add_attribute_monitor(self, obj, session, attr_name, oobfuncname, *args, **kwargs):
""" """
Monitor the changes of an Attribute on an object. Will trigger when Monitor the changes of an Attribute on an object. Will trigger when
the Attribute's `db_value` field updates. the Attribute's `db_value` field updates.
Args: Args:
obj (Object): Object with the Attribute to monitor. obj (Object): Object with the Attribute to monitor.
sessid (int): Session id of monitoring Session. session (Session): Session monitoring Session.
attr_name (str): Name (key) of Attribute to monitor. attr_name (str): Name (key) of Attribute to monitor.
oobfuncname (str): OOB function to call when Attribute updates. oobfuncname (str): OOB function to call when Attribute updates.
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
# get the attribute object if we can # get the attribute object if we can
attrobj = obj.attributes.get(attr_name, return_obj=True) attrobj = obj.attributes.get(attr_name, return_obj=True)
if attrobj: if attrobj:
self._add_monitor(attrobj, sessid, "db_value", oobfuncname) self._add_monitor(attrobj, sessid, "db_value", oobfuncname)
def remove_attribute_monitor(self, obj, sessid, attr_name, oobfuncname): def remove_attribute_monitor(self, obj, session, attr_name, oobfuncname):
""" """
Deactivate tracking for a given object's Attribute Deactivate tracking for a given object's Attribute
Args: Args:
obj (Object): Object monitored. obj (Object): Object monitored.
sessid (int): Session id of monitoring Session. session (Session): Session monitoring.
attr_name (str): Name of Attribute monitored. attr_name (str): Name of Attribute monitored.
oobfuncname (str): OOB function name called when Attribute updates. oobfuncname (str): OOB function name called when Attribute updates.
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
attrobj = obj.attributes.get(attr_name, return_obj=True) attrobj = obj.attributes.get(attr_name, return_obj=True)
if attrobj: if attrobj:
self._remove_monitor(attrobj, sessid, "db_value", oobfuncname) self._remove_monitor(attrobj, sessid, "db_value", oobfuncname)
def get_all_monitors(self, sessid): def get_all_monitors(self, session):
""" """
Get the names of all variables this session is tracking. Get the names of all variables this session is tracking.
Args: Args:
sessid (id): Session id of monitoring Session session (Session): Session monitoring.
Returns: Returns:
stored monitors (tuple): A list of tuples stored monitors (tuple): A list of tuples
`(obj, fieldname, args, kwargs)` representing all `(obj, fieldname, args, kwargs)` representing all
the monitoring the Session with the given sessid is doing. the monitoring the Session with the given sessid is doing.
""" """
# check so we didn't get a session instead of a sessid sessid = session.sessid
if not isinstance(sessid, int):
sessid = sessid.sessid
# [(obj, fieldname, args, kwargs), ...] # [(obj, fieldname, args, kwargs), ...]
return [(unpack_dbobj(key[0]), key[2], stored[0], stored[1]) return [(unpack_dbobj(key[0]), key[2], stored[0], stored[1])
for key, stored in self.oob_monitor_storage.items() if key[1] == sessid] for key, stored in self.oob_monitor_storage.items() if key[1] == sessid]
@ -441,9 +429,6 @@ class OOBHandler(TickerHandler):
`kwargs` are passed into the oob command. `kwargs` are passed into the oob command.
""" """
if isinstance(session, int):
# a sessid. Convert to a session
session = SESSIONS.session_from_sessid(session)
if not session: if not session:
errmsg = "OOB Error: execute_cmd(%s,%s,%s,%s) - no valid session" % \ errmsg = "OOB Error: execute_cmd(%s,%s,%s,%s) - no valid session" % \
(session, oobfuncname, args, kwargs) (session, oobfuncname, args, kwargs)

View file

@ -195,7 +195,7 @@ class PortalSessionHandler(SessionHandler):
protocol = cls(self, **config) protocol = cls(self, **config)
protocol.start() protocol.start()
def server_disconnect(self, sessid, reason=""): def server_disconnect(self, session, reason=""):
""" """
Called by server to force a disconnect by sessid. Called by server to force a disconnect by sessid.
@ -204,12 +204,11 @@ class PortalSessionHandler(SessionHandler):
reason (str, optional): Motivation for disconect. reason (str, optional): Motivation for disconect.
""" """
session = self.get(sessid, None)
if session: if session:
session.disconnect(reason) session.disconnect(reason)
if sessid in self: if session.sessid in self:
# in case sess.disconnect doesn't delete it # in case sess.disconnect doesn't delete it
del self[sessid] del self[session.sessid]
del session del session
def server_disconnect_all(self, reason=""): def server_disconnect_all(self, reason=""):
@ -225,18 +224,17 @@ class PortalSessionHandler(SessionHandler):
del session del session
self = {} self = {}
def server_logged_in(self, sessid, data): def server_logged_in(self, session, data):
""" """
The server tells us that the session has been authenticated. The server tells us that the session has been authenticated.
Update it. Called by the Server. Update it. Called by the Server.
Args: Args:
sessid (int): Session id logging in. session (Session): Session logging in.
data (dict): The session sync data. data (dict): The session sync data.
""" """
sess = self.get_session(sessid) session.load_sync_data(data)
sess.load_sync_data(data)
def server_session_sync(self, serversessions): def server_session_sync(self, serversessions):
""" """
@ -395,7 +393,7 @@ class PortalSessionHandler(SessionHandler):
if self.command_overflow: if self.command_overflow:
reactor.callLater(1.0, self.data_in, None) reactor.callLater(1.0, self.data_in, None)
if self.command_overflow: if self.command_overflow:
self.data_out(session.sessid, text=_ERROR_COMMAND_OVERFLOW) self.data_out(session, text=_ERROR_COMMAND_OVERFLOW)
return return
# relay data to Server # relay data to Server
self.command_counter += 1 self.command_counter += 1
@ -409,14 +407,14 @@ class PortalSessionHandler(SessionHandler):
reactor.callLater(1.0, self.data_in, None) reactor.callLater(1.0, self.data_in, None)
def data_out(self, sessid, text=None, **kwargs): def data_out(self, session, text=None, **kwargs):
""" """
Called by server for having the portal relay messages and data Called by server for having the portal relay messages and data
to the correct session protocol. We also convert oob input to to the correct session protocol. We also convert oob input to
a generic form here. a generic form here.
Args: Args:
sessid (int): Session id sending data. session (Session): Session sending data.
Kwargs: Kwargs:
text (str): Text from protocol. text (str): Text from protocol.
@ -426,7 +424,6 @@ class PortalSessionHandler(SessionHandler):
#from evennia.server.profiling.timetrace import timetrace #from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "portalsessionhandler.data_out") #text = timetrace(text, "portalsessionhandler.data_out")
session = self.get(sessid, None)
if session: if session:
# convert oob to the generic format # convert oob to the generic format
if "oob" in kwargs: if "oob" in kwargs:

View file

@ -202,7 +202,7 @@ class ServerSession(Session):
# done in the default @ic command but without any # done in the default @ic command but without any
# hooks, echoes or access checks. # hooks, echoes or access checks.
obj = _ObjectDB.objects.get(id=self.puid) obj = _ObjectDB.objects.get(id=self.puid)
obj.sessid.add(self.sessid) obj.sessions.add(self)
obj.player = self.player obj.player = self.player
self.puid = obj.id self.puid = obj.id
self.puppet = obj self.puppet = obj
@ -239,10 +239,9 @@ class ServerSession(Session):
""" """
if self.logged_in: if self.logged_in:
sessid = self.sessid
player = self.player player = self.player
if self.puppet: if self.puppet:
player.unpuppet_object(sessid) player.unpuppet_object(self)
uaccount = player uaccount = player
uaccount.last_login = timezone.now() uaccount.last_login = timezone.now()
uaccount.save() uaccount.save()
@ -363,14 +362,14 @@ class ServerSession(Session):
return return
if self.player: if self.player:
# nick replacement # nick replacement
puppet = self.player.get_puppet(self.sessid) puppet = self.puppet
if puppet: if puppet:
text = puppet.nicks.nickreplace(text, text = puppet.nicks.nickreplace(text,
categories=("inputline", "channel"), include_player=True) categories=("inputline", "channel"), include_player=True)
else: else:
text = self.player.nicks.nickreplace(text, text = self.player.nicks.nickreplace(text,
categories=("inputline", "channels"), include_player=False) categories=("inputline", "channels"), include_player=False)
cmdhandler(self, text, callertype="session", sessid=self.sessid) cmdhandler(self, text, callertype="session", session=self)
self.update_session_counters() self.update_session_counters()
execute_cmd = data_in # alias execute_cmd = data_in # alias

View file

@ -33,6 +33,9 @@ _ServerConfig = None
_ScriptDB = None _ScriptDB = None
_OOB_HANDLER = None _OOB_HANDLER = None
class DummySession(object):
sessid = 0
DUMMYSESSION = DummySession()
# AMP signals # AMP signals
PCONN = chr(1) # portal session connect PCONN = chr(1) # portal session connect
@ -55,6 +58,7 @@ _IDLE_TIMEOUT = settings.IDLE_TIMEOUT
_MAX_SERVER_COMMANDS_PER_SECOND = 100.0 _MAX_SERVER_COMMANDS_PER_SECOND = 100.0
_MAX_SESSION_COMMANDS_PER_SECOND = 5.0 _MAX_SESSION_COMMANDS_PER_SECOND = 5.0
def delayed_import(): def delayed_import():
""" """
Helper method for delayed import of all needed entities. Helper method for delayed import of all needed entities.
@ -264,7 +268,7 @@ class ServerSessionHandler(SessionHandler):
the Server. the Server.
""" """
self.server.amp_protocol.send_AdminServer2Portal(0, operation=SCONN, self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SCONN,
protocol_path=protocol_path, config=configdict) protocol_path=protocol_path, config=configdict)
def portal_shutdown(self): def portal_shutdown(self):
@ -272,7 +276,7 @@ class ServerSessionHandler(SessionHandler):
Called by server when shutting down the portal. Called by server when shutting down the portal.
""" """
self.server.amp_protocol.send_AdminServer2Portal(0, self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION,
operation=SSHUTD) operation=SSHUTD)
def login(self, session, player, testmode=False): def login(self, session, player, testmode=False):
@ -319,7 +323,7 @@ class ServerSessionHandler(SessionHandler):
session.logged_in = True session.logged_in = True
# sync the portal to the session # sync the portal to the session
if not testmode: if not testmode:
self.server.amp_protocol.send_AdminServer2Portal(session.sessid, self.server.amp_protocol.send_AdminServer2Portal(session,
operation=SLOGIN, operation=SLOGIN,
sessiondata={"logged_in": True}) sessiondata={"logged_in": True})
player.at_post_login(sessid=session.sessid) player.at_post_login(sessid=session.sessid)
@ -349,7 +353,7 @@ class ServerSessionHandler(SessionHandler):
sessid = session.sessid sessid = session.sessid
del self[sessid] del self[sessid]
# inform portal that session should be closed. # inform portal that session should be closed.
self.server.amp_protocol.send_AdminServer2Portal(sessid, self.server.amp_protocol.send_AdminServer2Portal(session,
operation=SDISCONN, operation=SDISCONN,
reason=reason) reason=reason)
@ -360,7 +364,7 @@ class ServerSessionHandler(SessionHandler):
""" """
sessdata = self.get_all_sync_data() sessdata = self.get_all_sync_data()
return self.server.amp_protocol.send_AdminServer2Portal(0, return self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION,
operation=SSYNC, operation=SSYNC,
sessiondata=sessdata) sessiondata=sessdata)
@ -376,7 +380,7 @@ class ServerSessionHandler(SessionHandler):
for session in self: for session in self:
del session del session
# tell portal to disconnect all sessions # tell portal to disconnect all sessions
self.server.amp_protocol.send_AdminServer2Portal(0, self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION,
operation=SDISCONNALL, operation=SDISCONNALL,
reason=reason) reason=reason)
@ -462,12 +466,9 @@ class ServerSessionHandler(SessionHandler):
sessions (Session or list): Session(s) found. sessions (Session or list): Session(s) found.
""" """
if is_iter(sessid): sessions = [self[sid] for sid in make_iter(sessid)
sessions = [self.get(sid) for sid in sessid] if sid in self and self[sid].logged_in and player.uid == self[sid].uid]
s = [sess for sess in sessions if sess and sess.logged_in and player.uid == sess.uid] return sessions[0] if len(sessions) == 1 else sessions
return s
session = self.get(sessid)
return session and session.logged_in and player.uid == session.uid and session or None
def sessions_from_player(self, player): def sessions_from_player(self, player):
""" """
@ -495,10 +496,8 @@ class ServerSessionHandler(SessionHandler):
more than one Session (MULTISESSION_MODE > 1). more than one Session (MULTISESSION_MODE > 1).
""" """
sessid = puppet.sessid.get() sessions = puppet.sessid.get()
if is_iter(sessid): return sessions[0] if len(sessions) == 1 else sessions
return [self.get(sid) for sid in sessid if sid in self]
return self.get(sessid)
sessions_from_character = sessions_from_puppet sessions_from_character = sessions_from_puppet
def announce_all(self, message): def announce_all(self, message):
@ -527,17 +526,17 @@ class ServerSessionHandler(SessionHandler):
text = text and to_str(to_unicode(text), encoding=session.encoding) text = text and to_str(to_unicode(text), encoding=session.encoding)
# send across AMP # send across AMP
self.server.amp_protocol.send_MsgServer2Portal(sessid=session.sessid, self.server.amp_protocol.send_MsgServer2Portal(session,
text=text, text=text,
**kwargs) **kwargs)
def data_in(self, sessid, text="", **kwargs): def data_in(self, session, text="", **kwargs):
""" """
Data Portal -> Server. Data Portal -> Server.
We also intercept OOB communication here. We also intercept OOB communication here.
Args: Args:
sessid (int): Session id. sessions (Session): Session.
Kwargs: Kwargs:
text (str): Text from protocol. text (str): Text from protocol.
@ -546,7 +545,6 @@ class ServerSessionHandler(SessionHandler):
""" """
#from evennia.server.profiling.timetrace import timetrace #from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "ServerSessionHandler.data_in") #text = timetrace(text, "ServerSessionHandler.data_in")
session = self.get(sessid, None)
if session: if session:
text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding) text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding)
if "oob" in kwargs: if "oob" in kwargs: