Merge remote-tracking branch 'upstream/master'

This commit is contained in:
luyijun 2014-10-22 00:37:49 +08:00
commit 73e57422c7
13 changed files with 66 additions and 34 deletions

View file

@ -346,7 +346,7 @@ node3 = MenuNode("node3", text=LOGIN_SCREEN_HELP,
class UnloggedInCmdSet(CmdSet):
"Cmdset for the unloggedin state"
key = "UnloggedinState"
key = "DefaultUnloggedin"
priority = 0
def at_cmdset_creation(self):
@ -361,6 +361,7 @@ class CmdUnloggedinLook(Command):
to the menu's own look command..
"""
key = CMD_LOGINSTART
aliases = ["look", "l"]
locks = "cmd:all()"
def func(self):

View file

@ -150,7 +150,7 @@ class MenuTree(object):
tree as needed. For safety, being in a menu will not survive a
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
upon first entering the menu. The endnode need not actually
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
track of which nodes it is connected to.
"""
menunode.init(self)
self.tree[menunode.key] = menunode
def goto(self, key):
@ -206,6 +205,8 @@ class MenuTree(object):
# not exiting, look for a valid code.
node = self.tree.get(key, None)
if node:
# initialize - this creates new cmdset
node.init(self)
if node.code:
# Execute eventual code active on this
# node. self.caller is available at this point.
@ -266,7 +267,7 @@ class MenuNode(object):
code block, as well as ev.
nodefaultcmds - if true, don't offer the default help and look commands
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.cmdset = None

View file

@ -62,8 +62,6 @@ def _init_command(mcs, **kwargs):
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
else:
mcs.arg_regex = None
if not hasattr(mcs, "auto_help"):
mcs.auto_help = True
if not hasattr(mcs, 'is_exit'):
@ -140,14 +138,16 @@ class Command(object):
locks = ""
# used by the help system to group commands in lists.
help_category = "general"
# This allows to turn off auto-help entry creation for individual commands.
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:
# obj - which object this command is defined on
# sessid - which session-id (if any) is responsible for
# triggering this command
#
# sessid - which session-id (if any) is responsible for triggering this command
def __init__(self, **kwargs):
"""the lockhandler works the same as for objects.

View file

@ -195,7 +195,7 @@ class TickerHandler(object):
self.save_name = save_name
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.
Returns a tuple (isdb, store_key) where isdb
@ -224,7 +224,7 @@ class TickerHandler(object):
objkey = id(obj)
isdb = False
# return sidb and store_key
return isdb, (objkey, interval)
return isdb, (objkey, interval, idstring)
def save(self):
"""
@ -237,9 +237,11 @@ class TickerHandler(object):
start_delays = dict((interval, ticker.task.next_call_time())
for interval, ticker in self.ticker_pool.tickers.items())
# 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)
ServerConfig.objects.conf(key=self.save_name,
value=dbserialize(self.ticker_storage))
else:
@ -254,30 +256,34 @@ class TickerHandler(object):
if ticker_storage:
self.ticker_storage = dbunserialize(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)
_, 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)
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
method. This will be called every interval seconds until the
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:
self.ticker_storage[store_key] = (args, kwargs)
self.save()
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
at a given interval.
"""
if interval:
isdb, store_key = self._store_key(obj, interval)
isdb, store_key = self._store_key(obj, interval, idstring)
if isdb:
self.ticker_storage.pop(store_key, None)
self.save()
@ -287,7 +293,7 @@ class TickerHandler(object):
intervals = self.ticker_pool.tickers.keys()
should_save = False
for interval in intervals:
isdb, store_key = self._store_key(obj, interval)
isdb, store_key = self._store_key(obj, interval, idstring)
if isdb:
self.ticker_storage.pop(store_key, None)
should_save = True

View file

@ -28,6 +28,10 @@ def mxp_parse(text):
"""
Replaces links to the correct format for MXP.
"""
text = text.replace("&", "&") \
.replace("<", "&lt;") \
.replace(">", "&gt;")
text = LINKS_SUB.sub(MXP_SEND, text)
return text
@ -47,6 +51,7 @@ class Mxp(object):
Client does not support MXP.
"""
self.protocol.protocol_flags["MXP"] = False
self.protocol.handshake_done()
def do_mxp(self, option):
"""

View file

@ -64,6 +64,15 @@ class PortalSessionHandler(SessionHandler):
# only use if session already has sessid (i.e. has already connected)
sessdata = session.get_sync_data()
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,
operation=PCONNSYNC,
data=sessdata)

View file

@ -50,6 +50,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
self.msdp = msdp.Msdp(self)
# mxp support
self.mxp = Mxp(self)
# keepalive watches for dead links
self.transport.setTcpKeepAlive(1)
# add this new connection to sessionhandler so
# the Server becomes aware of it.
self.sessionhandler.connect(self)
@ -258,6 +260,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
if prompt:
# Send prompt separately
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 += IAC + GA
self.transport.write(mccp_compress(self, prompt))

View file

@ -46,6 +46,8 @@ class WebSocketClient(Protocol, Session):
"""
client_address = self.transport.client
self.init_session("websocket", client_address, self.factory.sessionhandler)
# watch for dead links
self.transport.setTcpKeepAlive(1)
self.sessionhandler.connect(self)
def disconnect(self, reason=None):
@ -122,10 +124,10 @@ class WebSocketClient(Protocol, Session):
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
#print "oob data_out:", "OOB" + json.dumps(oobstruct)
self.sendLine("OOB" + json.dumps(oobstruct))
if "prompt" in kwargs:
self.sendLine("PROMPT" + kwargs["prompt"])
raw = kwargs.get("raw", False)
nomarkup = kwargs.get("nomarkup", False)
if "prompt" in kwargs:
self.sendLine("PROMPT" + parse_html(kwargs["prompt"], strip_ansi=nomarkup))
if raw:
self.sendLine(text)
else:

View file

@ -234,12 +234,6 @@ class ServerSession(Session):
Send Evennia -> User
"""
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)
def __eq__(self, other):

View file

@ -95,7 +95,7 @@ class Session(object):
and loads it into the correct properties of the session.
"""
for propname, value in sessdata.items():
self.__dict__[propname] = value
setattr(self, propname, value)
def at_sync(self):
"""

View file

@ -220,6 +220,11 @@ class ServerSessionHandler(SessionHandler):
sessid = portalsessiondata.get("sessid")
session = self.sessions.get(sessid)
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)
def portal_disconnect(self, sessid):
@ -339,7 +344,7 @@ class ServerSessionHandler(SessionHandler):
session.logged_in = True
# sync the portal to the session
sessdata = session.get_sync_data()
sessdata = {"logged_in": True}
if not testmode:
self.server.amp_protocol.call_remote_PortalAdmin(session.sessid,
operation=SLOGIN,
@ -407,7 +412,7 @@ class ServerSessionHandler(SessionHandler):
def validate_sessions(self):
"""
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()
reason = _("Idle timeout exceeded, disconnecting.")

View file

@ -305,11 +305,15 @@ def create_script(typeclass, key=None, obj=None, player=None, locks=None,
if persistent is not None:
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.
if autostart:
new_script.start()
new_db_script.save()
return new_script
#alias
script = create_script

View file

@ -782,7 +782,8 @@ def mod_import(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)
if not mod: