Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
73e57422c7
13 changed files with 66 additions and 34 deletions
|
|
@ -346,7 +346,7 @@ node3 = MenuNode("node3", text=LOGIN_SCREEN_HELP,
|
||||||
|
|
||||||
class UnloggedInCmdSet(CmdSet):
|
class UnloggedInCmdSet(CmdSet):
|
||||||
"Cmdset for the unloggedin state"
|
"Cmdset for the unloggedin state"
|
||||||
key = "UnloggedinState"
|
key = "DefaultUnloggedin"
|
||||||
priority = 0
|
priority = 0
|
||||||
|
|
||||||
def at_cmdset_creation(self):
|
def at_cmdset_creation(self):
|
||||||
|
|
@ -361,6 +361,7 @@ class CmdUnloggedinLook(Command):
|
||||||
to the menu's own look command..
|
to the menu's own look command..
|
||||||
"""
|
"""
|
||||||
key = CMD_LOGINSTART
|
key = CMD_LOGINSTART
|
||||||
|
aliases = ["look", "l"]
|
||||||
locks = "cmd:all()"
|
locks = "cmd:all()"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ class MenuTree(object):
|
||||||
tree as needed. For safety, being in a menu will not survive a
|
tree as needed. For safety, being in a menu will not survive a
|
||||||
server reboot.
|
server reboot.
|
||||||
|
|
||||||
A menutree have two special node keys given by 'startnode' and
|
A menutree has two special node keys given by 'startnode' and
|
||||||
'endnode' arguments. The startnode is where the user will start
|
'endnode' arguments. The startnode is where the user will start
|
||||||
upon first entering the menu. The endnode need not actually
|
upon first entering the menu. The endnode need not actually
|
||||||
exist, the moment it is linked to and that link is used, the menu
|
exist, the moment it is linked to and that link is used, the menu
|
||||||
|
|
@ -188,7 +188,6 @@ class MenuTree(object):
|
||||||
Add a menu node object to the tree. Each node itself keeps
|
Add a menu node object to the tree. Each node itself keeps
|
||||||
track of which nodes it is connected to.
|
track of which nodes it is connected to.
|
||||||
"""
|
"""
|
||||||
menunode.init(self)
|
|
||||||
self.tree[menunode.key] = menunode
|
self.tree[menunode.key] = menunode
|
||||||
|
|
||||||
def goto(self, key):
|
def goto(self, key):
|
||||||
|
|
@ -206,6 +205,8 @@ class MenuTree(object):
|
||||||
# not exiting, look for a valid code.
|
# not exiting, look for a valid code.
|
||||||
node = self.tree.get(key, None)
|
node = self.tree.get(key, None)
|
||||||
if node:
|
if node:
|
||||||
|
# initialize - this creates new cmdset
|
||||||
|
node.init(self)
|
||||||
if node.code:
|
if node.code:
|
||||||
# Execute eventual code active on this
|
# Execute eventual code active on this
|
||||||
# node. self.caller is available at this point.
|
# node. self.caller is available at this point.
|
||||||
|
|
@ -266,7 +267,7 @@ class MenuNode(object):
|
||||||
code block, as well as ev.
|
code block, as well as ev.
|
||||||
nodefaultcmds - if true, don't offer the default help and look commands
|
nodefaultcmds - if true, don't offer the default help and look commands
|
||||||
in the node
|
in the node
|
||||||
separator - this string will be put on the line between menu nodes5B.
|
separator - this string will be put on the line between menu nodes.
|
||||||
"""
|
"""
|
||||||
self.key = key
|
self.key = key
|
||||||
self.cmdset = None
|
self.cmdset = None
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,6 @@ def _init_command(mcs, **kwargs):
|
||||||
|
|
||||||
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
|
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
|
||||||
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
|
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
|
||||||
else:
|
|
||||||
mcs.arg_regex = None
|
|
||||||
if not hasattr(mcs, "auto_help"):
|
if not hasattr(mcs, "auto_help"):
|
||||||
mcs.auto_help = True
|
mcs.auto_help = True
|
||||||
if not hasattr(mcs, 'is_exit'):
|
if not hasattr(mcs, 'is_exit'):
|
||||||
|
|
@ -140,14 +138,16 @@ class Command(object):
|
||||||
locks = ""
|
locks = ""
|
||||||
# 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 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
|
auto_help = True
|
||||||
|
# optimization for quickly separating exit-commands from normal commands
|
||||||
|
is_exit = False
|
||||||
|
# define the command not only by key but by the regex form of its arguments
|
||||||
|
arg_regex = None
|
||||||
|
|
||||||
# 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
|
# sessid - which session-id (if any) is responsible for triggering this command
|
||||||
# triggering this command
|
|
||||||
#
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""the lockhandler works the same as for objects.
|
"""the lockhandler works the same as for objects.
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ class TickerHandler(object):
|
||||||
self.save_name = save_name
|
self.save_name = save_name
|
||||||
self.ticker_pool = self.ticker_pool_class()
|
self.ticker_pool = self.ticker_pool_class()
|
||||||
|
|
||||||
def _store_key(self, obj, interval):
|
def _store_key(self, obj, interval, idstring=""):
|
||||||
"""
|
"""
|
||||||
Tries to create a store_key for the object.
|
Tries to create a store_key for the object.
|
||||||
Returns a tuple (isdb, store_key) where isdb
|
Returns a tuple (isdb, store_key) where isdb
|
||||||
|
|
@ -224,7 +224,7 @@ class TickerHandler(object):
|
||||||
objkey = id(obj)
|
objkey = id(obj)
|
||||||
isdb = False
|
isdb = False
|
||||||
# return sidb and store_key
|
# return sidb and store_key
|
||||||
return isdb, (objkey, interval)
|
return isdb, (objkey, interval, idstring)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -237,9 +237,11 @@ class TickerHandler(object):
|
||||||
start_delays = dict((interval, ticker.task.next_call_time())
|
start_delays = dict((interval, ticker.task.next_call_time())
|
||||||
for interval, ticker in self.ticker_pool.tickers.items())
|
for interval, ticker in self.ticker_pool.tickers.items())
|
||||||
# update the timers for the tickers
|
# update the timers for the tickers
|
||||||
for (obj, interval), (args, kwargs) in self.ticker_storage.items():
|
#for (obj, interval, idstring), (args, kwargs) in self.ticker_storage.items():
|
||||||
|
for store_key, (args, kwargs) in self.ticker_storage.items():
|
||||||
|
interval = store_key[1]
|
||||||
|
# this is a mutable, so it's updated in-place in ticker_storage
|
||||||
kwargs["_start_delay"] = start_delays.get(interval, None)
|
kwargs["_start_delay"] = start_delays.get(interval, None)
|
||||||
|
|
||||||
ServerConfig.objects.conf(key=self.save_name,
|
ServerConfig.objects.conf(key=self.save_name,
|
||||||
value=dbserialize(self.ticker_storage))
|
value=dbserialize(self.ticker_storage))
|
||||||
else:
|
else:
|
||||||
|
|
@ -254,30 +256,34 @@ class TickerHandler(object):
|
||||||
if ticker_storage:
|
if ticker_storage:
|
||||||
self.ticker_storage = dbunserialize(ticker_storage)
|
self.ticker_storage = dbunserialize(ticker_storage)
|
||||||
#print "restore:", self.ticker_storage
|
#print "restore:", self.ticker_storage
|
||||||
for (obj, interval), (args, kwargs) in self.ticker_storage.items():
|
for store_key, (args, kwargs) in self.ticker_storage.items():
|
||||||
|
if len(store_key) == 2:
|
||||||
|
# old form of store_key - update it
|
||||||
|
store_key = (store_key[0], store_key[1], "")
|
||||||
|
obj, interval, idstring = store_key
|
||||||
obj = unpack_dbobj(obj)
|
obj = unpack_dbobj(obj)
|
||||||
_, store_key = self._store_key(obj, interval)
|
_, store_key = self._store_key(obj, interval, idstring)
|
||||||
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
||||||
|
|
||||||
def add(self, obj, interval, *args, **kwargs):
|
def add(self, obj, interval, idstring="", *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Add object to tickerhandler. The object must have an at_tick
|
Add object to tickerhandler. The object must have an at_tick
|
||||||
method. This will be called every interval seconds until the
|
method. This will be called every interval seconds until the
|
||||||
object is unsubscribed from the ticker.
|
object is unsubscribed from the ticker.
|
||||||
"""
|
"""
|
||||||
isdb, store_key = self._store_key(obj, interval)
|
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||||
if isdb:
|
if isdb:
|
||||||
self.ticker_storage[store_key] = (args, kwargs)
|
self.ticker_storage[store_key] = (args, kwargs)
|
||||||
self.save()
|
self.save()
|
||||||
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
||||||
|
|
||||||
def remove(self, obj, interval=None):
|
def remove(self, obj, interval=None, idstring=""):
|
||||||
"""
|
"""
|
||||||
Remove object from ticker, or only this object ticking
|
Remove object from ticker, or only this object ticking
|
||||||
at a given interval.
|
at a given interval.
|
||||||
"""
|
"""
|
||||||
if interval:
|
if interval:
|
||||||
isdb, store_key = self._store_key(obj, interval)
|
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||||
if isdb:
|
if isdb:
|
||||||
self.ticker_storage.pop(store_key, None)
|
self.ticker_storage.pop(store_key, None)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
@ -287,7 +293,7 @@ class TickerHandler(object):
|
||||||
intervals = self.ticker_pool.tickers.keys()
|
intervals = self.ticker_pool.tickers.keys()
|
||||||
should_save = False
|
should_save = False
|
||||||
for interval in intervals:
|
for interval in intervals:
|
||||||
isdb, store_key = self._store_key(obj, interval)
|
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||||
if isdb:
|
if isdb:
|
||||||
self.ticker_storage.pop(store_key, None)
|
self.ticker_storage.pop(store_key, None)
|
||||||
should_save = True
|
should_save = True
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ def mxp_parse(text):
|
||||||
"""
|
"""
|
||||||
Replaces links to the correct format for MXP.
|
Replaces links to the correct format for MXP.
|
||||||
"""
|
"""
|
||||||
|
text = text.replace("&", "&") \
|
||||||
|
.replace("<", "<") \
|
||||||
|
.replace(">", ">")
|
||||||
|
|
||||||
text = LINKS_SUB.sub(MXP_SEND, text)
|
text = LINKS_SUB.sub(MXP_SEND, text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
@ -47,6 +51,7 @@ class Mxp(object):
|
||||||
Client does not support MXP.
|
Client does not support MXP.
|
||||||
"""
|
"""
|
||||||
self.protocol.protocol_flags["MXP"] = False
|
self.protocol.protocol_flags["MXP"] = False
|
||||||
|
self.protocol.handshake_done()
|
||||||
|
|
||||||
def do_mxp(self, option):
|
def do_mxp(self, option):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,15 @@ class PortalSessionHandler(SessionHandler):
|
||||||
# only use if session already has sessid (i.e. has already connected)
|
# only use if session already has sessid (i.e. has already connected)
|
||||||
sessdata = session.get_sync_data()
|
sessdata = session.get_sync_data()
|
||||||
if self.portal.amp_protocol:
|
if self.portal.amp_protocol:
|
||||||
|
# we only send sessdata that should not have changed
|
||||||
|
# at the server level at this point
|
||||||
|
sessdata = dict((key, val) for key, val in sessdata.items() if key in ("protocol_key",
|
||||||
|
"address",
|
||||||
|
"sessid",
|
||||||
|
"suid",
|
||||||
|
"conn_time",
|
||||||
|
"protocol_flags",
|
||||||
|
"server_data",))
|
||||||
self.portal.amp_protocol.call_remote_ServerAdmin(session.sessid,
|
self.portal.amp_protocol.call_remote_ServerAdmin(session.sessid,
|
||||||
operation=PCONNSYNC,
|
operation=PCONNSYNC,
|
||||||
data=sessdata)
|
data=sessdata)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
||||||
self.msdp = msdp.Msdp(self)
|
self.msdp = msdp.Msdp(self)
|
||||||
# mxp support
|
# mxp support
|
||||||
self.mxp = Mxp(self)
|
self.mxp = Mxp(self)
|
||||||
|
# keepalive watches for dead links
|
||||||
|
self.transport.setTcpKeepAlive(1)
|
||||||
# add this new connection to sessionhandler so
|
# add this new connection to sessionhandler so
|
||||||
# the Server becomes aware of it.
|
# the Server becomes aware of it.
|
||||||
self.sessionhandler.connect(self)
|
self.sessionhandler.connect(self)
|
||||||
|
|
@ -258,6 +260,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
||||||
if prompt:
|
if prompt:
|
||||||
# Send prompt separately
|
# Send prompt separately
|
||||||
prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256)
|
prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256)
|
||||||
|
if mxp:
|
||||||
|
prompt = mxp_parse(prompt)
|
||||||
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
|
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
|
||||||
prompt += IAC + GA
|
prompt += IAC + GA
|
||||||
self.transport.write(mccp_compress(self, prompt))
|
self.transport.write(mccp_compress(self, prompt))
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ class WebSocketClient(Protocol, Session):
|
||||||
"""
|
"""
|
||||||
client_address = self.transport.client
|
client_address = self.transport.client
|
||||||
self.init_session("websocket", client_address, self.factory.sessionhandler)
|
self.init_session("websocket", client_address, self.factory.sessionhandler)
|
||||||
|
# watch for dead links
|
||||||
|
self.transport.setTcpKeepAlive(1)
|
||||||
self.sessionhandler.connect(self)
|
self.sessionhandler.connect(self)
|
||||||
|
|
||||||
def disconnect(self, reason=None):
|
def disconnect(self, reason=None):
|
||||||
|
|
@ -122,10 +124,10 @@ class WebSocketClient(Protocol, Session):
|
||||||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
|
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
|
||||||
#print "oob data_out:", "OOB" + json.dumps(oobstruct)
|
#print "oob data_out:", "OOB" + json.dumps(oobstruct)
|
||||||
self.sendLine("OOB" + json.dumps(oobstruct))
|
self.sendLine("OOB" + json.dumps(oobstruct))
|
||||||
if "prompt" in kwargs:
|
|
||||||
self.sendLine("PROMPT" + kwargs["prompt"])
|
|
||||||
raw = kwargs.get("raw", False)
|
raw = kwargs.get("raw", False)
|
||||||
nomarkup = kwargs.get("nomarkup", False)
|
nomarkup = kwargs.get("nomarkup", False)
|
||||||
|
if "prompt" in kwargs:
|
||||||
|
self.sendLine("PROMPT" + parse_html(kwargs["prompt"], strip_ansi=nomarkup))
|
||||||
if raw:
|
if raw:
|
||||||
self.sendLine(text)
|
self.sendLine(text)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -234,12 +234,6 @@ class ServerSession(Session):
|
||||||
Send Evennia -> User
|
Send Evennia -> User
|
||||||
"""
|
"""
|
||||||
text = text if text else ""
|
text = text if text else ""
|
||||||
#if text is None:
|
|
||||||
# text = ""
|
|
||||||
#else:
|
|
||||||
# text = to_unicode(text)
|
|
||||||
# text = to_str(text, self.encoding)
|
|
||||||
|
|
||||||
self.sessionhandler.data_out(self, text=text, **kwargs)
|
self.sessionhandler.data_out(self, text=text, **kwargs)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ class Session(object):
|
||||||
and loads it into the correct properties of the session.
|
and loads it into the correct properties of the session.
|
||||||
"""
|
"""
|
||||||
for propname, value in sessdata.items():
|
for propname, value in sessdata.items():
|
||||||
self.__dict__[propname] = value
|
setattr(self, propname, value)
|
||||||
|
|
||||||
def at_sync(self):
|
def at_sync(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,11 @@ class ServerSessionHandler(SessionHandler):
|
||||||
sessid = portalsessiondata.get("sessid")
|
sessid = portalsessiondata.get("sessid")
|
||||||
session = self.sessions.get(sessid)
|
session = self.sessions.get(sessid)
|
||||||
if session:
|
if session:
|
||||||
|
# since some of the session properties may have had
|
||||||
|
# a chance to change already before the portal gets here
|
||||||
|
# the portal doesn't send all sessiondata here, but only
|
||||||
|
# ones which should only be changed from portal (like
|
||||||
|
# protocol_flags etc)
|
||||||
session.load_sync_data(portalsessiondata)
|
session.load_sync_data(portalsessiondata)
|
||||||
|
|
||||||
def portal_disconnect(self, sessid):
|
def portal_disconnect(self, sessid):
|
||||||
|
|
@ -339,7 +344,7 @@ class ServerSessionHandler(SessionHandler):
|
||||||
|
|
||||||
session.logged_in = True
|
session.logged_in = True
|
||||||
# sync the portal to the session
|
# sync the portal to the session
|
||||||
sessdata = session.get_sync_data()
|
sessdata = {"logged_in": True}
|
||||||
if not testmode:
|
if not testmode:
|
||||||
self.server.amp_protocol.call_remote_PortalAdmin(session.sessid,
|
self.server.amp_protocol.call_remote_PortalAdmin(session.sessid,
|
||||||
operation=SLOGIN,
|
operation=SLOGIN,
|
||||||
|
|
@ -407,7 +412,7 @@ class ServerSessionHandler(SessionHandler):
|
||||||
def validate_sessions(self):
|
def validate_sessions(self):
|
||||||
"""
|
"""
|
||||||
Check all currently connected sessions (logged in and not)
|
Check all currently connected sessions (logged in and not)
|
||||||
and see if any are dead.
|
and see if any are dead or idle
|
||||||
"""
|
"""
|
||||||
tcurr = time.time()
|
tcurr = time.time()
|
||||||
reason = _("Idle timeout exceeded, disconnecting.")
|
reason = _("Idle timeout exceeded, disconnecting.")
|
||||||
|
|
|
||||||
|
|
@ -305,11 +305,15 @@ def create_script(typeclass, key=None, obj=None, player=None, locks=None,
|
||||||
if persistent is not None:
|
if persistent is not None:
|
||||||
new_script.persistent = persistent
|
new_script.persistent = persistent
|
||||||
|
|
||||||
|
# must do this before starting the script since some
|
||||||
|
# scripts may otherwise run for a very short time and
|
||||||
|
# try to delete itself before we have a time to save it.
|
||||||
|
new_db_script.save()
|
||||||
|
|
||||||
# a new created script should usually be started.
|
# a new created script should usually be started.
|
||||||
if autostart:
|
if autostart:
|
||||||
new_script.start()
|
new_script.start()
|
||||||
|
|
||||||
new_db_script.save()
|
|
||||||
return new_script
|
return new_script
|
||||||
#alias
|
#alias
|
||||||
script = create_script
|
script = create_script
|
||||||
|
|
|
||||||
|
|
@ -782,7 +782,8 @@ def mod_import(module):
|
||||||
|
|
||||||
def all_from_module(module):
|
def all_from_module(module):
|
||||||
"""
|
"""
|
||||||
Return all global-level variables from a module as a dict
|
Return all global-level variables from a module as a dict.
|
||||||
|
Ignores modules and variable names starting with an underscore.
|
||||||
"""
|
"""
|
||||||
mod = mod_import(module)
|
mod = mod_import(module)
|
||||||
if not mod:
|
if not mod:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue