Merge conflicts against master, including cmdhandler support for direct cmdobject input together with prefix-ignore mechanism from devel.
This commit is contained in:
commit
a648433db8
69 changed files with 2617 additions and 1771 deletions
|
|
@ -7,7 +7,7 @@ The separation works like this:
|
|||
|
||||
Portal - (AMP client) handles protocols. It contains a list of connected
|
||||
sessions in a dictionary for identifying the respective player
|
||||
connected. If it looses the AMP connection it will automatically
|
||||
connected. If it loses the AMP connection it will automatically
|
||||
try to reconnect.
|
||||
|
||||
Server - (AMP server) Handles all mud operations. The server holds its own list
|
||||
|
|
@ -32,33 +32,33 @@ from twisted.internet import protocol
|
|||
from twisted.internet.defer import Deferred
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import to_str, variable_from_module
|
||||
import zlib # Used in Compressed class
|
||||
|
||||
DUMMYSESSION = namedtuple('DummySession', ['sessid'])(0)
|
||||
|
||||
# communication bits
|
||||
# (chr(9) and chr(10) are \t and \n, so skipping them)
|
||||
|
||||
PCONN = chr(1) # portal session connect
|
||||
PDISCONN = chr(2) # portal session disconnect
|
||||
PSYNC = chr(3) # portal session sync
|
||||
SLOGIN = chr(4) # server session login
|
||||
SDISCONN = chr(5) # server session disconnect
|
||||
SDISCONNALL = chr(6) # server session disconnect all
|
||||
SSHUTD = chr(7) # server shutdown
|
||||
SSYNC = chr(8) # server session sync
|
||||
PCONN = chr(1) # portal session connect
|
||||
PDISCONN = chr(2) # portal session disconnect
|
||||
PSYNC = chr(3) # portal session sync
|
||||
SLOGIN = chr(4) # server session login
|
||||
SDISCONN = chr(5) # server session disconnect
|
||||
SDISCONNALL = chr(6) # server session disconnect all
|
||||
SSHUTD = chr(7) # server shutdown
|
||||
SSYNC = chr(8) # server session sync
|
||||
SCONN = chr(11) # server creating new connection (for irc bots and etc)
|
||||
PCONNSYNC = chr(12) # portal post-syncing a session
|
||||
PDISCONNALL = chr(13) # portal session disconnect all
|
||||
PCONNSYNC = chr(12) # portal post-syncing a session
|
||||
PDISCONNALL = chr(13) # portal session disconnect all
|
||||
AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed)
|
||||
|
||||
BATCH_RATE = 250 # max commands/sec before switching to batch-sending
|
||||
BATCH_TIMEOUT = 0.5 # how often to poll to empty batch queue, in seconds
|
||||
BATCH_RATE = 250 # max commands/sec before switching to batch-sending
|
||||
BATCH_TIMEOUT = 0.5 # how often to poll to empty batch queue, in seconds
|
||||
|
||||
# buffers
|
||||
_SENDBATCH = defaultdict(list)
|
||||
_MSGBUFFER = defaultdict(list)
|
||||
|
||||
import zlib
|
||||
|
||||
def get_restart_mode(restart_file):
|
||||
"""
|
||||
|
|
@ -323,9 +323,9 @@ dumps = lambda data: to_str(pickle.dumps(to_str(data), pickle.HIGHEST_PROTOCOL))
|
|||
loads = lambda data: pickle.loads(to_str(data))
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
# Core AMP protocol for communication Server <-> Portal
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
|
||||
class AMPProtocol(amp.AMP):
|
||||
"""
|
||||
|
|
@ -385,7 +385,6 @@ class AMPProtocol(amp.AMP):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
# Error handling
|
||||
|
||||
def errback(self, e, info):
|
||||
|
|
@ -447,7 +446,7 @@ class AMPProtocol(amp.AMP):
|
|||
Access method called by the Portal and executed on the Portal.
|
||||
|
||||
Args:
|
||||
sessid (int): Unique Session id.
|
||||
session (session): Session
|
||||
kwargs (any, optional): Optional data.
|
||||
|
||||
Returns:
|
||||
|
|
@ -473,7 +472,6 @@ class AMPProtocol(amp.AMP):
|
|||
self.factory.portal.sessions.data_out(session, **kwargs)
|
||||
return {}
|
||||
|
||||
|
||||
def send_MsgServer2Portal(self, session, **kwargs):
|
||||
"""
|
||||
Access method - executed on the Server for sending data
|
||||
|
|
@ -506,7 +504,7 @@ class AMPProtocol(amp.AMP):
|
|||
# create a new session and sync it
|
||||
server_sessionhandler.portal_connect(kwargs.get("sessiondata"))
|
||||
|
||||
elif operation == PCONNSYNC: #portal_session_sync
|
||||
elif operation == PCONNSYNC: # portal_session_sync
|
||||
server_sessionhandler.portal_session_sync(kwargs.get("sessiondata"))
|
||||
|
||||
elif operation == PDISCONN: # portal_session_disconnect
|
||||
|
|
@ -515,7 +513,7 @@ class AMPProtocol(amp.AMP):
|
|||
if session:
|
||||
server_sessionhandler.portal_disconnect(session)
|
||||
|
||||
elif operation == PDISCONNALL: # portal_disconnect_all
|
||||
elif operation == PDISCONNALL: # portal_disconnect_all
|
||||
# portal orders all sessions to close
|
||||
server_sessionhandler.portal_disconnect_all()
|
||||
|
||||
|
|
@ -545,7 +543,7 @@ class AMPProtocol(amp.AMP):
|
|||
"""
|
||||
return self.send_data(AdminPortal2Server, session.sessid, operation=operation, **kwargs)
|
||||
|
||||
# Portal administraton from the Server side
|
||||
# Portal administration from the Server side
|
||||
|
||||
@AdminServer2Portal.responder
|
||||
def portal_receive_adminserver2portal(self, packed_data):
|
||||
|
|
@ -562,7 +560,6 @@ class AMPProtocol(amp.AMP):
|
|||
operation = kwargs.pop("operation")
|
||||
portal_sessionhandler = self.factory.portal.sessions
|
||||
|
||||
|
||||
if operation == SLOGIN: # server_session_login
|
||||
# a session has authenticated; sync it.
|
||||
session = portal_sessionhandler.get(sessid)
|
||||
|
|
@ -591,7 +588,7 @@ class AMPProtocol(amp.AMP):
|
|||
# set a flag in case we are about to shut down soon
|
||||
self.factory.server_restart_mode = True
|
||||
|
||||
elif operation == SCONN: # server_force_connection (for irc/etc)
|
||||
elif operation == SCONN: # server_force_connection (for irc/etc)
|
||||
portal_sessionhandler.server_connect(**kwargs)
|
||||
|
||||
else:
|
||||
|
|
@ -665,4 +662,5 @@ class AMPProtocol(amp.AMP):
|
|||
module=modulepath,
|
||||
function=functionname,
|
||||
args=dumps(args),
|
||||
kwargs=dumps(kwargs)).addCallback(lambda r: loads(r["result"])).addErrback(self.errback, "FunctionCall")
|
||||
kwargs=dumps(kwargs)).addCallback(
|
||||
lambda r: loads(r["result"])).addErrback(self.errback, "FunctionCall")
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ from evennia.server.models import ServerConfig
|
|||
from evennia.utils import create, logger
|
||||
|
||||
|
||||
ERROR_NO_SUPERUSER = \
|
||||
"""
|
||||
ERROR_NO_SUPERUSER = """
|
||||
No superuser exists yet. The superuser is the 'owner' account on
|
||||
the Evennia server. Create a new superuser using the command
|
||||
|
||||
|
|
@ -26,16 +25,14 @@ ERROR_NO_SUPERUSER = \
|
|||
"""
|
||||
|
||||
|
||||
LIMBO_DESC = \
|
||||
_("""
|
||||
Welcome to your new {wEvennia{n-based game! Visit http://www.evennia.com if you need
|
||||
LIMBO_DESC = _("""
|
||||
Welcome to your new |wEvennia|n-based game! Visit http://www.evennia.com if you need
|
||||
help, want to contribute, report issues or just join the community.
|
||||
As Player #1 you can create a demo/tutorial area with {w@batchcommand tutorial_world.build{n.
|
||||
As Player #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n.
|
||||
""")
|
||||
|
||||
|
||||
WARNING_POSTGRESQL_FIX = \
|
||||
"""
|
||||
WARNING_POSTGRESQL_FIX = """
|
||||
PostgreSQL-psycopg2 compatibility fix:
|
||||
The in-game channels {chan1}, {chan2} and {chan3} were created,
|
||||
but the superuser was not yet connected to them. Please use in
|
||||
|
|
|
|||
|
|
@ -40,18 +40,23 @@ IRC_MAGENTA = "13"
|
|||
IRC_DGREY = "14"
|
||||
IRC_GRAY = "15"
|
||||
|
||||
# test:
|
||||
# obsolete test:
|
||||
# {rred {ggreen {yyellow {bblue {mmagenta {ccyan {wwhite {xdgrey
|
||||
# {Rdred {Gdgreen {Ydyellow {Bdblue {Mdmagenta {Cdcyan {Wlgrey {Xblack
|
||||
# {[rredbg {[ggreenbg {[yyellowbg {[bbluebg {[mmagentabg {[ccyanbg {[wlgreybg {[xblackbg
|
||||
|
||||
# test:
|
||||
# |rred |ggreen |yyellow |bblue |mmagenta |ccyan |wwhite |xdgrey
|
||||
# |Rdred |Gdgreen |Ydyellow |Bdblue |Mdmagenta |Cdcyan |Wlgrey |Xblack
|
||||
# |[rredbg |[ggreenbg |[yyellowbg |[bbluebg |[mmagentabg |[ccyanbg |[wlgreybg |[xblackbg
|
||||
|
||||
IRC_COLOR_MAP = dict([
|
||||
# obs - {-type colors are deprecated but still used in many places.
|
||||
(r'{n', IRC_RESET), # reset
|
||||
(r'{n', IRC_RESET), # reset
|
||||
(r'{/', ""), # line break
|
||||
(r'{-', " "), # tab
|
||||
(r'{_', " "), # space
|
||||
(r'{*', ""), # invert
|
||||
(r'{-', " "), # tab
|
||||
(r'{_', " "), # space
|
||||
(r'{*', ""), # invert
|
||||
(r'{^', ""), # blinking text
|
||||
|
||||
(r'{r', IRC_COLOR + IRC_RED),
|
||||
|
|
@ -69,7 +74,7 @@ IRC_COLOR_MAP = dict([
|
|||
(r'{B', IRC_COLOR + IRC_DBLUE),
|
||||
(r'{M', IRC_COLOR + IRC_DMAGENTA),
|
||||
(r'{C', IRC_COLOR + IRC_DCYAN),
|
||||
(r'{W', IRC_COLOR + IRC_GRAY), # light grey
|
||||
(r'{W', IRC_COLOR + IRC_GRAY), # light grey
|
||||
(r'{X', IRC_COLOR + IRC_BLACK), # pure black
|
||||
|
||||
(r'{[r', IRC_COLOR + IRC_NORMAL + "," + IRC_DRED),
|
||||
|
|
@ -79,14 +84,14 @@ IRC_COLOR_MAP = dict([
|
|||
(r'{[m', IRC_COLOR + IRC_NORMAL + "," + IRC_DMAGENTA),
|
||||
(r'{[c', IRC_COLOR + IRC_NORMAL + "," + IRC_DCYAN),
|
||||
(r'{[w', IRC_COLOR + IRC_NORMAL + "," + IRC_GRAY), # light grey background
|
||||
(r'{[x', IRC_COLOR + IRC_NORMAL + "," + IRC_BLACK), # pure black background
|
||||
(r'{[x', IRC_COLOR + IRC_NORMAL + "," + IRC_BLACK), # pure black background
|
||||
|
||||
# |-type formatting is the thing to use.
|
||||
(r'|n', IRC_RESET), # reset
|
||||
(r'|n', IRC_RESET), # reset
|
||||
(r'|/', ""), # line break
|
||||
(r'|-', " "), # tab
|
||||
(r'|_', " "), # space
|
||||
(r'|*', ""), # invert
|
||||
(r'|-', " "), # tab
|
||||
(r'|_', " "), # space
|
||||
(r'|*', ""), # invert
|
||||
(r'|^', ""), # blinking text
|
||||
|
||||
(r'|r', IRC_COLOR + IRC_RED),
|
||||
|
|
@ -104,7 +109,7 @@ IRC_COLOR_MAP = dict([
|
|||
(r'|B', IRC_COLOR + IRC_DBLUE),
|
||||
(r'|M', IRC_COLOR + IRC_DMAGENTA),
|
||||
(r'|C', IRC_COLOR + IRC_DCYAN),
|
||||
(r'|W', IRC_COLOR + IRC_GRAY), # light grey
|
||||
(r'|W', IRC_COLOR + IRC_GRAY), # light grey
|
||||
(r'|X', IRC_COLOR + IRC_BLACK), # pure black
|
||||
|
||||
(r'|[r', IRC_COLOR + IRC_NORMAL + "," + IRC_DRED),
|
||||
|
|
@ -114,12 +119,13 @@ IRC_COLOR_MAP = dict([
|
|||
(r'|[m', IRC_COLOR + IRC_NORMAL + "," + IRC_DMAGENTA),
|
||||
(r'|[c', IRC_COLOR + IRC_NORMAL + "," + IRC_DCYAN),
|
||||
(r'|[w', IRC_COLOR + IRC_NORMAL + "," + IRC_GRAY), # light grey background
|
||||
(r'|[x', IRC_COLOR + IRC_NORMAL + "," + IRC_BLACK) # pure black background
|
||||
(r'|[x', IRC_COLOR + IRC_NORMAL + "," + IRC_BLACK) # pure black background
|
||||
])
|
||||
RE_IRC_COLOR = re.compile(r"|".join([re.escape(key) for key in viewkeys(IRC_COLOR_MAP)]), re.DOTALL)
|
||||
RE_MXP = re.compile(r'\{lc(.*?)\{lt(.*?)\{le', re.DOTALL)
|
||||
RE_MXP = re.compile(r'\|lc(.*?)\|lt(.*?)\|le', re.DOTALL)
|
||||
RE_ANSI_ESCAPES = re.compile(r"(%s)" % "|".join(("{{", "%%", "\\\\")), re.DOTALL)
|
||||
|
||||
|
||||
def sub_irc(ircmatch):
|
||||
"""
|
||||
Substitute irc color info. Used by re.sub.
|
||||
|
|
@ -133,6 +139,7 @@ def sub_irc(ircmatch):
|
|||
"""
|
||||
return IRC_COLOR_MAP.get(ircmatch.group(), "")
|
||||
|
||||
|
||||
def parse_irc_colors(string):
|
||||
"""
|
||||
Parse {-type syntax and replace with IRC color markers
|
||||
|
|
@ -156,9 +163,10 @@ def parse_irc_colors(string):
|
|||
|
||||
# IRC bot
|
||||
|
||||
|
||||
class IRCBot(irc.IRCClient, Session):
|
||||
"""
|
||||
An IRC bot that tracks actitivity in a channel as well
|
||||
An IRC bot that tracks activity in a channel as well
|
||||
as sends text to it when prompted
|
||||
|
||||
"""
|
||||
|
|
@ -190,7 +198,7 @@ class IRCBot(irc.IRCClient, Session):
|
|||
logger.log_info("IRC bot '%s' connected to %s at %s:%s." % (self.nickname, self.channel,
|
||||
self.network, self.port))
|
||||
|
||||
def disconnect(self, reason=None):
|
||||
def disconnect(self, reason=""):
|
||||
"""
|
||||
Called by sessionhandler to disconnect this protocol.
|
||||
|
||||
|
|
@ -198,7 +206,7 @@ class IRCBot(irc.IRCClient, Session):
|
|||
reason (str): Motivation for the disconnect.
|
||||
|
||||
"""
|
||||
self.sessionhandler.disconnect(self)
|
||||
self.sessionhandler.disconnect(self, reason=reason)
|
||||
self.stopping = True
|
||||
self.transport.loseConnection()
|
||||
|
||||
|
|
@ -246,14 +254,14 @@ class IRCBot(irc.IRCClient, Session):
|
|||
self.sendLine("NAMES %s" % self.channel)
|
||||
|
||||
def irc_RPL_NAMREPLY(self, prefix, params):
|
||||
"Handles IRC NAME request returns (nicklist)"
|
||||
""""Handles IRC NAME request returns (nicklist)"""
|
||||
channel = params[2].lower()
|
||||
if channel != self.channel.lower():
|
||||
return
|
||||
self.nicklist += params[3].split(' ')
|
||||
|
||||
def irc_RPL_ENDOFNAMES(self, prefix, params):
|
||||
"Called when the nicklist has finished being returned."
|
||||
"""Called when the nicklist has finished being returned."""
|
||||
channel = params[1].lower()
|
||||
if channel != self.channel.lower():
|
||||
return
|
||||
|
|
@ -271,7 +279,6 @@ class IRCBot(irc.IRCClient, Session):
|
|||
"""
|
||||
self.data_in(text="", type="ping", user="server", channel=self.channel, timing=time)
|
||||
|
||||
|
||||
def data_in(self, text=None, **kwargs):
|
||||
"""
|
||||
Data IRC -> Server.
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ if os.name == 'nt':
|
|||
# For Windows we need to handle pid files manually.
|
||||
PORTAL_PIDFILE = os.path.join(settings.GAME_DIR, "server", 'portal.pid')
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
# Evennia Portal settings
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
|
||||
VERSION = get_evennia_version()
|
||||
|
||||
|
|
@ -76,6 +76,8 @@ AMP_ENABLED = AMP_HOST and AMP_PORT and AMP_INTERFACE
|
|||
# Maintenance function - this is called repeatedly by the portal.
|
||||
|
||||
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
|
||||
|
||||
def _portal_maintenance():
|
||||
"""
|
||||
The maintenance function handles repeated checks and updates that
|
||||
|
|
@ -94,12 +96,12 @@ def _portal_maintenance():
|
|||
if _IDLE_TIMEOUT > 0:
|
||||
# only start the maintenance task if we care about idling.
|
||||
_maintenance_task = LoopingCall(_portal_maintenance)
|
||||
_maintenance_task.start(60) # called every minute
|
||||
_maintenance_task.start(60) # called every minute
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
# Portal Service object
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
class Portal(object):
|
||||
|
||||
"""
|
||||
|
|
@ -180,11 +182,11 @@ class Portal(object):
|
|||
self.shutdown_complete = True
|
||||
reactor.callLater(0, reactor.stop)
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
#
|
||||
# Start the Portal proxy server and add all active services
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
|
||||
# twistd requires us to define the variable 'application' so it knows
|
||||
# what to execute from.
|
||||
|
|
|
|||
|
|
@ -28,9 +28,11 @@ _CONNECTION_QUEUE = deque()
|
|||
|
||||
DUMMYSESSION = namedtuple('DummySession', ['sessid'])(0)
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
# Portal-SessionHandler class
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
|
||||
|
||||
class PortalSessionHandler(SessionHandler):
|
||||
"""
|
||||
This object holds the sessions connected to the portal at any time.
|
||||
|
|
@ -95,7 +97,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
if len(_CONNECTION_QUEUE) > 1:
|
||||
session.data_out(text=[["%s DoS protection is active. You are queued to connect in %g seconds ..." % (
|
||||
settings.SERVERNAME,
|
||||
len(_CONNECTION_QUEUE)*_MIN_TIME_BETWEEN_CONNECTS)],{}])
|
||||
len(_CONNECTION_QUEUE)*_MIN_TIME_BETWEEN_CONNECTS)], {}])
|
||||
now = time.time()
|
||||
if (now - self.connection_last < _MIN_TIME_BETWEEN_CONNECTS) or not self.portal.amp_protocol:
|
||||
if not session or not self.connection_task:
|
||||
|
|
@ -176,8 +178,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
del self[session.sessid]
|
||||
|
||||
# Tell the Server to disconnect its version of the Session as well.
|
||||
self.portal.amp_protocol.send_AdminPortal2Server(session,
|
||||
operation=PDISCONN)
|
||||
self.portal.amp_protocol.send_AdminPortal2Server(session, operation=PDISCONN)
|
||||
|
||||
def disconnect_all(self):
|
||||
"""
|
||||
|
|
@ -194,7 +195,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
# inform Server; wait until finished sending before we continue
|
||||
# removing all the sessions.
|
||||
self.portal.amp_protocol.send_AdminPortal2Server(DUMMYSESSION,
|
||||
operation=PDISCONNALL).addCallback(_callback, self)
|
||||
operation=PDISCONNALL).addCallback(_callback, self)
|
||||
|
||||
def server_connect(self, protocol_path="", config=dict()):
|
||||
"""
|
||||
|
|
@ -233,8 +234,8 @@ class PortalSessionHandler(SessionHandler):
|
|||
Called by server to force a disconnect by sessid.
|
||||
|
||||
Args:
|
||||
sessid (int): Session id to disconnect.
|
||||
reason (str, optional): Motivation for disconect.
|
||||
session (portalsession): Session to disconnect.
|
||||
reason (str, optional): Motivation for disconnect.
|
||||
|
||||
"""
|
||||
if session:
|
||||
|
|
@ -335,7 +336,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
|
||||
"""
|
||||
for session in self.values():
|
||||
self.data_out(session, text=[[message],{}])
|
||||
self.data_out(session, text=[[message], {}])
|
||||
|
||||
def data_in(self, session, **kwargs):
|
||||
"""
|
||||
|
|
@ -352,8 +353,8 @@ class PortalSessionHandler(SessionHandler):
|
|||
Data is serialized before passed on.
|
||||
|
||||
"""
|
||||
#from evennia.server.profiling.timetrace import timetrace
|
||||
#text = timetrace(text, "portalsessionhandler.data_in")
|
||||
# from evennia.server.profiling.timetrace import timetrace # DEBUG
|
||||
# text = timetrace(text, "portalsessionhandler.data_in") # DEBUG
|
||||
try:
|
||||
text = kwargs['text']
|
||||
if (_MAX_CHAR_LIMIT > 0) and len(text) > _MAX_CHAR_LIMIT:
|
||||
|
|
@ -365,16 +366,16 @@ class PortalSessionHandler(SessionHandler):
|
|||
pass
|
||||
if session:
|
||||
now = time.time()
|
||||
if self.command_counter > _MAX_COMMAND_RATE:
|
||||
if self.command_counter > _MAX_COMMAND_RATE > 0:
|
||||
# data throttle (anti DoS measure)
|
||||
dT = now - self.command_counter_reset
|
||||
delta_time = now - self.command_counter_reset
|
||||
self.command_counter = 0
|
||||
self.command_counter_reset = now
|
||||
self.command_overflow = dT < 1.0
|
||||
self.command_overflow = delta_time < 1.0
|
||||
if self.command_overflow:
|
||||
reactor.callLater(1.0, self.data_in, None)
|
||||
if self.command_overflow:
|
||||
self.data_out(session, text=[[_ERROR_COMMAND_OVERFLOW],{}])
|
||||
self.data_out(session, text=[[_ERROR_COMMAND_OVERFLOW], {}])
|
||||
return
|
||||
# scrub data
|
||||
kwargs = self.clean_senddata(session, kwargs)
|
||||
|
|
@ -385,7 +386,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
self.portal.amp_protocol.send_MsgPortal2Server(session,
|
||||
**kwargs)
|
||||
else:
|
||||
# called by the callLater callback
|
||||
# called by the callLater callback
|
||||
if self.command_overflow:
|
||||
self.command_overflow = False
|
||||
reactor.callLater(1.0, self.data_in, None)
|
||||
|
|
@ -405,8 +406,8 @@ class PortalSessionHandler(SessionHandler):
|
|||
method exixts, it sends the data to a method send_default.
|
||||
|
||||
"""
|
||||
#from evennia.server.profiling.timetrace import timetrace
|
||||
#text = timetrace(text, "portalsessionhandler.data_out")
|
||||
# from evennia.server.profiling.timetrace import timetrace # DEBUG
|
||||
# text = timetrace(text, "portalsessionhandler.data_out") # DEBUG
|
||||
|
||||
# distribute outgoing data to the correct session methods.
|
||||
if session:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ packages).
|
|||
try:
|
||||
from twisted.conch.ssh.keys import Key
|
||||
except ImportError:
|
||||
raise ImportError (_SSH_IMPORT_ERROR)
|
||||
raise ImportError(_SSH_IMPORT_ERROR)
|
||||
|
||||
from twisted.conch.ssh.userauth import SSHUserAuthServer
|
||||
from twisted.conch.ssh import common
|
||||
|
|
@ -49,7 +49,7 @@ from evennia.players.models import PlayerDB
|
|||
from evennia.utils import ansi
|
||||
from evennia.utils.utils import to_str
|
||||
|
||||
_RE_N = re.compile(r"\{n$")
|
||||
_RE_N = re.compile(r"\|n$")
|
||||
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
|
||||
_GAME_DIR = settings.GAME_DIR
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ class SshProtocol(Manhole, session.Session):
|
|||
|
||||
"""
|
||||
for line in string.split('\n'):
|
||||
#this is the telnet-specific method for sending
|
||||
# the telnet-specific method for sending
|
||||
self.terminal.write(line)
|
||||
self.terminal.nextLine()
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ class SshProtocol(Manhole, session.Session):
|
|||
Note that it must be actively turned back on again!
|
||||
|
||||
"""
|
||||
#print "telnet.send_text", args,kwargs
|
||||
# print "telnet.send_text", args,kwargs # DEBUG
|
||||
text = args[0] if args else ""
|
||||
if text is None:
|
||||
return
|
||||
|
|
@ -268,8 +268,8 @@ class SshProtocol(Manhole, session.Session):
|
|||
useansi = options.get("ansi", flags.get('ANSI', True))
|
||||
raw = options.get("raw", flags.get("RAW", False))
|
||||
nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi))
|
||||
#echo = options.get("echo", None)
|
||||
screenreader = options.get("screenreader", flags.get("SCREENREADER", False))
|
||||
# echo = options.get("echo", None) # DEBUG
|
||||
screenreader = options.get("screenreader", flags.get("SCREENREADER", False))
|
||||
|
||||
if screenreader:
|
||||
# screenreader mode cleans up output
|
||||
|
|
@ -283,7 +283,8 @@ class SshProtocol(Manhole, session.Session):
|
|||
else:
|
||||
# we need to make sure to kill the color at the end in order
|
||||
# to match the webclient output.
|
||||
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nocolor, xterm256=xterm256, mxp=False)
|
||||
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + ("|n" if text[-1] != "|" else "||n"),
|
||||
strip_ansi=nocolor, xterm256=xterm256, mxp=False)
|
||||
self.sendLine(linetosend)
|
||||
|
||||
def send_prompt(self, *args, **kwargs):
|
||||
|
|
@ -453,11 +454,10 @@ def makeFactory(configdict):
|
|||
factory.publicKeys = {'ssh-rsa': publicKey}
|
||||
factory.privateKeys = {'ssh-rsa': privateKey}
|
||||
except Exception as err:
|
||||
print ( "getKeyPair error: {err}\n WARNING: Evennia could not " \
|
||||
"auto-generate SSH keypair. Using conch default keys instead.\n" \
|
||||
"If this error persists, create {pub} and " \
|
||||
"{priv} yourself using third-party tools.".format(
|
||||
err=err, pub=pubkeyfile, priv=privkeyfile))
|
||||
print("getKeyPair error: {err}\n WARNING: Evennia could not "
|
||||
"auto-generate SSH keypair. Using conch default keys instead.\n"
|
||||
"If this error persists, create {pub} and "
|
||||
"{priv} yourself using third-party tools.".format(err=err, pub=pubkeyfile, priv=privkeyfile))
|
||||
|
||||
factory.services = factory.services.copy()
|
||||
factory.services['ssh-userauth'] = ExtraInfoAuthServer
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ class SSLProtocol(TelnetProtocol):
|
|||
super(SSLProtocol, self).__init__(*args, **kwargs)
|
||||
self.protocol_name = "ssl"
|
||||
|
||||
|
||||
def verify_SSL_key_and_cert(keyfile, certfile):
|
||||
"""
|
||||
This function looks for RSA key and certificate in the current
|
||||
|
|
@ -82,7 +83,7 @@ def verify_SSL_key_and_cert(keyfile, certfile):
|
|||
# try to create the certificate
|
||||
CERT_EXPIRE = 365 * 20 # twenty years validity
|
||||
# default:
|
||||
#openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300
|
||||
# openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300
|
||||
exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (keyfile, certfile, CERT_EXPIRE)
|
||||
try:
|
||||
subprocess.call(exestring)
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@ from evennia.server.portal.mxp import Mxp, mxp_parse
|
|||
from evennia.utils import ansi
|
||||
from evennia.utils.utils import to_str
|
||||
|
||||
_RE_N = re.compile(r"\{n$")
|
||||
_RE_N = re.compile(r"\|n$")
|
||||
_RE_LEND = re.compile(r"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
|
||||
_RE_LINEBREAK = re.compile(r"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE)
|
||||
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
|
||||
_IDLE_COMMAND = settings.IDLE_COMMAND + "\n"
|
||||
|
||||
|
||||
class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
||||
"""
|
||||
Each player connecting over telnet (ie using most traditional mud
|
||||
|
|
@ -46,7 +47,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
client_address = client_address[0] if client_address else None
|
||||
# this number is counted down for every handshake that completes.
|
||||
# when it reaches 0 the portal/server syncs their data
|
||||
self.handshakes = 7 # naws, ttype, mccp, mssp, msdp, gmcp, mxp
|
||||
self.handshakes = 7 # naws, ttype, mccp, mssp, msdp, gmcp, mxp
|
||||
self.init_session(self.protocol_name, client_address, self.factory.sessionhandler)
|
||||
|
||||
# negotiate client size
|
||||
|
|
@ -79,7 +80,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
self.toggle_nop_keepalive()
|
||||
|
||||
def _send_nop_keepalive(self):
|
||||
"Send NOP keepalive unless flag is set"
|
||||
"""Send NOP keepalive unless flag is set"""
|
||||
if self.protocol_flags.get("NOPKEEPALIVE"):
|
||||
self._write(IAC + NOP)
|
||||
|
||||
|
|
@ -140,7 +141,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
enable (bool): If this option should be enabled.
|
||||
|
||||
"""
|
||||
return (option == MCCP or option==ECHO)
|
||||
return option == MCCP or option == ECHO
|
||||
|
||||
def disableLocal(self, option):
|
||||
"""
|
||||
|
|
@ -178,7 +179,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
directly.
|
||||
|
||||
Args:
|
||||
string (str): Incoming data.
|
||||
data (str): Incoming data.
|
||||
|
||||
"""
|
||||
if not data:
|
||||
|
|
@ -188,7 +189,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
# legacy clients. There should never be a reason to send a
|
||||
# lone NULL character so this seems to be a safe thing to
|
||||
# support for backwards compatibility. It also stops the
|
||||
# NULL from continously popping up as an unknown command.
|
||||
# NULL from continuously popping up as an unknown command.
|
||||
data = [_IDLE_COMMAND]
|
||||
else:
|
||||
data = _RE_LINEBREAK.split(data)
|
||||
|
|
@ -205,7 +206,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
self.data_in(text=dat + "\n")
|
||||
|
||||
def _write(self, data):
|
||||
"hook overloading the one used in plain telnet"
|
||||
"""hook overloading the one used in plain telnet"""
|
||||
data = data.replace('\n', '\r\n').replace('\r\r\n', '\r\n')
|
||||
super(TelnetProtocol, self)._write(mccp_compress(self, data))
|
||||
|
||||
|
|
@ -217,24 +218,23 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
line (str): Line to send.
|
||||
|
||||
"""
|
||||
#escape IAC in line mode, and correctly add \r\n
|
||||
# escape IAC in line mode, and correctly add \r\n
|
||||
line += self.delimiter
|
||||
line = line.replace(IAC, IAC + IAC).replace('\n', '\r\n')
|
||||
return self.transport.write(mccp_compress(self, line))
|
||||
|
||||
|
||||
# Session hooks
|
||||
|
||||
def disconnect(self, reason=None):
|
||||
def disconnect(self, reason=""):
|
||||
"""
|
||||
generic hook for the engine to call in order to
|
||||
disconnect this protocol.
|
||||
|
||||
Args:
|
||||
reason (str): Reason for disconnecting.
|
||||
reason (str, optional): Reason for disconnecting.
|
||||
|
||||
"""
|
||||
self.data_out(text=((reason or "",), {}))
|
||||
self.data_out(text=((reason,), {}))
|
||||
self.connectionLost(reason)
|
||||
|
||||
def data_in(self, **kwargs):
|
||||
|
|
@ -245,8 +245,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
kwargs (any): Options from the protocol.
|
||||
|
||||
"""
|
||||
#from evennia.server.profiling.timetrace import timetrace
|
||||
#text = timetrace(text, "telnet.data_in")
|
||||
# from evennia.server.profiling.timetrace import timetrace # DEBUG
|
||||
# text = timetrace(text, "telnet.data_in") # DEBUG
|
||||
|
||||
self.sessionhandler.data_in(self, **kwargs)
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi))
|
||||
echo = options.get("echo", None)
|
||||
mxp = options.get("mxp", flags.get("MXP", False))
|
||||
screenreader = options.get("screenreader", flags.get("SCREENREADER", False))
|
||||
screenreader = options.get("screenreader", flags.get("SCREENREADER", False))
|
||||
|
||||
if screenreader:
|
||||
# screenreader mode cleans up output
|
||||
|
|
@ -306,9 +306,11 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
|
||||
if options.get("send_prompt"):
|
||||
# send a prompt instead.
|
||||
prompt = text
|
||||
if not raw:
|
||||
# processing
|
||||
prompt = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nocolor, xterm256=xterm256)
|
||||
prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + ("|n" if prompt[-1] != "|" else "||n"),
|
||||
strip_ansi=nocolor, xterm256=xterm256)
|
||||
if mxp:
|
||||
prompt = mxp_parse(prompt)
|
||||
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
|
||||
|
|
@ -335,7 +337,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
else:
|
||||
# we need to make sure to kill the color at the end in order
|
||||
# to match the webclient output.
|
||||
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nocolor, xterm256=xterm256, mxp=mxp)
|
||||
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + ("|n" if text[-1] != "|" else "||n"),
|
||||
strip_ansi=nocolor, xterm256=xterm256, mxp=mxp)
|
||||
if mxp:
|
||||
linetosend = mxp_parse(linetosend)
|
||||
self.sendLine(linetosend)
|
||||
|
|
@ -348,7 +351,6 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
kwargs["options"].update({"send_prompt": True})
|
||||
self.send_text(*args, **kwargs)
|
||||
|
||||
|
||||
def send_default(self, cmdname, *args, **kwargs):
|
||||
"""
|
||||
Send other oob data
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ from evennia.utils.utils import to_str
|
|||
|
||||
# MSDP-relevant telnet cmd/opt-codes
|
||||
MSDP = chr(69)
|
||||
MSDP_VAR = chr(1) #^A
|
||||
MSDP_VAL = chr(2) #^B
|
||||
MSDP_TABLE_OPEN = chr(3) #^C
|
||||
MSDP_TABLE_CLOSE = chr(4) #^D
|
||||
MSDP_ARRAY_OPEN = chr(5) #^E
|
||||
MSDP_ARRAY_CLOSE = chr(6) #^F
|
||||
MSDP_VAR = chr(1) # ^A
|
||||
MSDP_VAL = chr(2) # ^B
|
||||
MSDP_TABLE_OPEN = chr(3) # ^C
|
||||
MSDP_TABLE_CLOSE = chr(4) # ^D
|
||||
MSDP_ARRAY_OPEN = chr(5) # ^E
|
||||
MSDP_ARRAY_CLOSE = chr(6) # ^F
|
||||
|
||||
# GMCP
|
||||
GMCP = chr(201)
|
||||
|
|
@ -51,13 +51,15 @@ force_str = lambda inp: to_str(inp, force_string=True)
|
|||
|
||||
# pre-compiled regexes
|
||||
# returns 2-tuple
|
||||
msdp_regex_table = re.compile(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL,
|
||||
MSDP_TABLE_OPEN,
|
||||
MSDP_TABLE_CLOSE))
|
||||
msdp_regex_table = re.compile(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s"
|
||||
% (MSDP_VAR, MSDP_VAL,
|
||||
MSDP_TABLE_OPEN,
|
||||
MSDP_TABLE_CLOSE))
|
||||
# returns 2-tuple
|
||||
msdp_regex_array = re.compile(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL,
|
||||
MSDP_ARRAY_OPEN,
|
||||
MSDP_ARRAY_CLOSE))
|
||||
msdp_regex_array = re.compile(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s"
|
||||
% (MSDP_VAR, MSDP_VAL,
|
||||
MSDP_ARRAY_OPEN,
|
||||
MSDP_ARRAY_CLOSE))
|
||||
msdp_regex_var = re.compile(r"%s" % MSDP_VAR)
|
||||
msdp_regex_val = re.compile(r"%s" % MSDP_VAL)
|
||||
|
||||
|
|
@ -67,7 +69,8 @@ EVENNIA_TO_GMCP = {"client_options": "Core.Supports.Get",
|
|||
"repeat": "Char.Repeat.Update",
|
||||
"monitor": "Char.Monitor.Update"}
|
||||
|
||||
# Msdp object handler
|
||||
|
||||
# MSDP/GMCP communication handler
|
||||
|
||||
class TelnetOOB(object):
|
||||
"""
|
||||
|
|
@ -100,7 +103,7 @@ class TelnetOOB(object):
|
|||
Client reports No msdp supported or wanted.
|
||||
|
||||
Args:
|
||||
options (Option): Not used.
|
||||
option (Option): Not used.
|
||||
|
||||
"""
|
||||
# no msdp, check GMCP
|
||||
|
|
@ -173,7 +176,7 @@ class TelnetOOB(object):
|
|||
if not (args or kwargs):
|
||||
return msdp_cmdname
|
||||
|
||||
#print "encode_msdp in:", cmdname, args, kwargs
|
||||
# print("encode_msdp in:", cmdname, args, kwargs) # DEBUG
|
||||
|
||||
msdp_args = ''
|
||||
if args:
|
||||
|
|
@ -182,30 +185,30 @@ class TelnetOOB(object):
|
|||
msdp_args += args[0]
|
||||
else:
|
||||
msdp_args += "{msdp_array_open}" \
|
||||
"{msdp_args}" \
|
||||
"{msdp_array_close}".format(
|
||||
msdp_array_open=MSDP_ARRAY_OPEN,
|
||||
msdp_array_close=MSDP_ARRAY_CLOSE,
|
||||
msdp_args= "".join("%s%s" % (
|
||||
MSDP_VAL, json.dumps(val))
|
||||
for val in args))
|
||||
|
||||
"{msdp_args}" \
|
||||
"{msdp_array_close}".format(
|
||||
msdp_array_open=MSDP_ARRAY_OPEN,
|
||||
msdp_array_close=MSDP_ARRAY_CLOSE,
|
||||
msdp_args="".join("%s%s"
|
||||
% (MSDP_VAL, json.dumps(val))
|
||||
for val in args))
|
||||
|
||||
msdp_kwargs = ""
|
||||
if kwargs:
|
||||
msdp_kwargs = msdp_cmdname
|
||||
msdp_kwargs += "{msdp_table_open}" \
|
||||
"{msdp_kwargs}" \
|
||||
"{msdp_table_close}".format(
|
||||
msdp_table_open=MSDP_TABLE_OPEN,
|
||||
msdp_table_close=MSDP_TABLE_CLOSE,
|
||||
msdp_kwargs = "".join("%s%s%s%s" % (
|
||||
MSDP_VAR, key, MSDP_VAL, json.dumps(val))
|
||||
for key, val in kwargs.iteritems()))
|
||||
"{msdp_kwargs}" \
|
||||
"{msdp_table_close}".format(
|
||||
msdp_table_open=MSDP_TABLE_OPEN,
|
||||
msdp_table_close=MSDP_TABLE_CLOSE,
|
||||
msdp_kwargs="".join("%s%s%s%s"
|
||||
% (MSDP_VAR, key, MSDP_VAL,
|
||||
json.dumps(val))
|
||||
for key, val in kwargs.iteritems()))
|
||||
|
||||
msdp_string = msdp_args + msdp_kwargs
|
||||
|
||||
#print "msdp_string:", msdp_string
|
||||
# print("msdp_string:", msdp_string) # DEBUG
|
||||
return msdp_string
|
||||
|
||||
def encode_gmcp(self, cmdname, *args, **kwargs):
|
||||
|
|
@ -238,10 +241,10 @@ class TelnetOOB(object):
|
|||
gmcp_string = "%s %s" % (cmdname, json.dumps([args, kwargs]))
|
||||
else:
|
||||
gmcp_string = "%s %s" % (cmdname, json.dumps(args))
|
||||
else: # only kwargs
|
||||
else: # only kwargs
|
||||
gmcp_string = "%s %s" % (cmdname, json.dumps(kwargs))
|
||||
|
||||
#print "gmcp string", gmcp_string
|
||||
# print("gmcp string", gmcp_string) # DEBUG
|
||||
return gmcp_string
|
||||
|
||||
def decode_msdp(self, data):
|
||||
|
|
@ -271,7 +274,7 @@ class TelnetOOB(object):
|
|||
if hasattr(data, "__iter__"):
|
||||
data = "".join(data)
|
||||
|
||||
#print "decode_msdp in:", data
|
||||
# print("decode_msdp in:", data) # DEBUG
|
||||
|
||||
tables = {}
|
||||
arrays = {}
|
||||
|
|
@ -279,7 +282,7 @@ class TelnetOOB(object):
|
|||
|
||||
# decode tables
|
||||
for key, table in msdp_regex_table.findall(data):
|
||||
tables[key] = {} if not key in tables else tables[key]
|
||||
tables[key] = {} if key not in tables else tables[key]
|
||||
for varval in msdp_regex_var.split(table)[1:]:
|
||||
var, val = msdp_regex_val.split(varval, 1)
|
||||
if var:
|
||||
|
|
@ -288,7 +291,7 @@ class TelnetOOB(object):
|
|||
# decode arrays from all that was not a table
|
||||
data_no_tables = msdp_regex_table.sub("", data)
|
||||
for key, array in msdp_regex_array.findall(data_no_tables):
|
||||
arrays[key] = [] if not key in arrays else arrays[key]
|
||||
arrays[key] = [] if key not in arrays else arrays[key]
|
||||
parts = msdp_regex_val.split(array)
|
||||
if len(parts) == 2:
|
||||
arrays[key].append(parts[1])
|
||||
|
|
@ -326,10 +329,9 @@ class TelnetOOB(object):
|
|||
for key, var in variables.iteritems():
|
||||
cmds[key] = [[var], {}]
|
||||
|
||||
#print "msdp data in:", cmds
|
||||
# print("msdp data in:", cmds) # DEBUG
|
||||
self.protocol.data_in(**cmds)
|
||||
|
||||
|
||||
def decode_gmcp(self, data):
|
||||
"""
|
||||
Decodes incoming GMCP data on the form 'varname <structure>'.
|
||||
|
|
@ -353,7 +355,7 @@ class TelnetOOB(object):
|
|||
if hasattr(data, "__iter__"):
|
||||
data = "".join(data)
|
||||
|
||||
#print "decode_gmcp in:", data
|
||||
# print("decode_gmcp in:", data) # DEBUG
|
||||
if data:
|
||||
try:
|
||||
cmdname, structure = data.split(None, 1)
|
||||
|
|
@ -368,7 +370,7 @@ class TelnetOOB(object):
|
|||
args, kwargs = [], {}
|
||||
if hasattr(structure, "__iter__"):
|
||||
if isinstance(structure, dict):
|
||||
kwargs = {key: value for key, value in structure.iteritems() if key }
|
||||
kwargs = {key: value for key, value in structure.iteritems() if key}
|
||||
else:
|
||||
args = list(structure)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ MTTS = [(128, 'PROXY'),
|
|||
(2, 'VT100'),
|
||||
(1, 'ANSI')]
|
||||
|
||||
|
||||
class Ttype(object):
|
||||
"""
|
||||
Handles ttype negotiations. Called and initiated by the
|
||||
|
|
@ -104,22 +105,21 @@ class Ttype(object):
|
|||
# use name to identify support for xterm256. Many of these
|
||||
# only support after a certain version, but all support
|
||||
# it since at least 4 years. We assume recent client here for now.
|
||||
xterm256 = False
|
||||
cupper = clientname.upper()
|
||||
if cupper.startswith("MUDLET"):
|
||||
# supports xterm256 stably since 1.1 (2010?)
|
||||
xterm256 = cupper.split("MUDLET",1)[1].strip() >= "1.1"
|
||||
xterm256 = cupper.split("MUDLET", 1)[1].strip() >= "1.1"
|
||||
else:
|
||||
xterm256 = (cupper.startswith("XTERM") or
|
||||
cupper.endswith("-256COLOR") or
|
||||
cupper in ("ATLANTIS", # > 0.9.9.0 (aug 2009)
|
||||
"CMUD", # > 3.04 (mar 2009)
|
||||
"KILDCLIENT", # > 2.2.0 (sep 2005)
|
||||
"MUDLET", # > beta 15 (sep 2009)
|
||||
"MUSHCLIENT", # > 4.02 (apr 2007)
|
||||
"PUTTY", # > 0.58 (apr 2005)
|
||||
"BEIP", # > 2.00.206 (late 2009) (BeipMu)
|
||||
"POTATO")) # > 2.00 (maybe earlier)
|
||||
"CMUD", # > 3.04 (mar 2009)
|
||||
"KILDCLIENT", # > 2.2.0 (sep 2005)
|
||||
"MUDLET", # > beta 15 (sep 2009)
|
||||
"MUSHCLIENT", # > 4.02 (apr 2007)
|
||||
"PUTTY", # > 0.58 (apr 2005)
|
||||
"BEIP", # > 2.00.206 (late 2009) (BeipMu)
|
||||
"POTATO")) # > 2.00 (maybe earlier)
|
||||
|
||||
# all clients supporting TTYPE at all seem to support ANSI
|
||||
self.protocol.protocol_flags['ANSI'] = True
|
||||
|
|
|
|||
|
|
@ -32,8 +32,9 @@ from django.utils.translation import ugettext as _
|
|||
|
||||
# Handlers for Session.db/ndb operation
|
||||
|
||||
|
||||
class NDbHolder(object):
|
||||
"Holder for allowing property access of attributes"
|
||||
"""Holder for allowing property access of attributes"""
|
||||
def __init__(self, obj, name, manager_name='attributes'):
|
||||
_SA(self, name, _GA(obj, manager_name))
|
||||
_SA(self, 'name', name)
|
||||
|
|
@ -145,9 +146,9 @@ class NAttributeHandler(object):
|
|||
return [key for key in self._store if not key.startswith("_")]
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
# Server Session
|
||||
#------------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
|
||||
class ServerSession(Session):
|
||||
"""
|
||||
|
|
@ -160,7 +161,7 @@ class ServerSession(Session):
|
|||
|
||||
"""
|
||||
def __init__(self):
|
||||
"Initiate to avoid AttributeErrors down the line"
|
||||
"""Initiate to avoid AttributeErrors down the line"""
|
||||
self.puppet = None
|
||||
self.player = None
|
||||
self.cmdset_storage_string = ""
|
||||
|
|
@ -203,7 +204,7 @@ class ServerSession(Session):
|
|||
obj.player = self.player
|
||||
self.puid = obj.id
|
||||
self.puppet = obj
|
||||
#obj.scripts.validate()
|
||||
# obj.scripts.validate()
|
||||
obj.locks.cache_lock_bypass(obj)
|
||||
|
||||
def at_login(self, player):
|
||||
|
|
@ -264,7 +265,6 @@ class ServerSession(Session):
|
|||
MONITOR_HANDLER.remove(player, "_saved_webclient_options",
|
||||
self.sessid)
|
||||
|
||||
|
||||
def get_player(self):
|
||||
"""
|
||||
Get the player associated with this session
|
||||
|
|
@ -364,7 +364,6 @@ class ServerSession(Session):
|
|||
self.protocol_flags.update(kwargs)
|
||||
self.sessionhandler.session_portal_sync(self)
|
||||
|
||||
|
||||
def data_out(self, **kwargs):
|
||||
"""
|
||||
Sending data from Evennia->Client
|
||||
|
|
@ -437,7 +436,7 @@ class ServerSession(Session):
|
|||
self.sessionhandler.data_in(self, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
"Handle session comparisons"
|
||||
"""Handle session comparisons"""
|
||||
try:
|
||||
return self.address == other.address
|
||||
except AttributeError:
|
||||
|
|
@ -462,11 +461,9 @@ class ServerSession(Session):
|
|||
return "%s%s@%s" % (self.uname, symbol, address)
|
||||
|
||||
def __unicode__(self):
|
||||
"Unicode representation"
|
||||
"""Unicode representation"""
|
||||
return u"%s" % str(self)
|
||||
|
||||
|
||||
|
||||
# Dummy API hooks for use during non-loggedin operation
|
||||
|
||||
def at_cmdset_get(self, **kwargs):
|
||||
|
|
@ -488,7 +485,7 @@ class ServerSession(Session):
|
|||
def attributes(self):
|
||||
return self.nattributes
|
||||
|
||||
#@property
|
||||
# @property
|
||||
def ndb_get(self):
|
||||
"""
|
||||
A non-persistent store (ndb: NonDataBase). Everything stored
|
||||
|
|
@ -503,7 +500,7 @@ class ServerSession(Session):
|
|||
self._ndb_holder = NDbHolder(self, "nattrhandler", manager_name="nattributes")
|
||||
return self._ndb_holder
|
||||
|
||||
#@ndb.setter
|
||||
# @ndb.setter
|
||||
def ndb_set(self, value):
|
||||
"""
|
||||
Stop accidentally replacing the db object
|
||||
|
|
@ -516,9 +513,9 @@ class ServerSession(Session):
|
|||
string += "Use ndb.attr=value instead."
|
||||
raise Exception(string)
|
||||
|
||||
#@ndb.deleter
|
||||
# @ndb.deleter
|
||||
def ndb_del(self):
|
||||
"Stop accidental deletion."
|
||||
"""Stop accidental deletion."""
|
||||
raise Exception("Cannot delete the ndb object!")
|
||||
ndb = property(ndb_get, ndb_set, ndb_del)
|
||||
db = property(ndb_get, ndb_set, ndb_del)
|
||||
|
|
@ -526,5 +523,5 @@ class ServerSession(Session):
|
|||
# Mock access method for the session (there is no lock info
|
||||
# at this stage, so we just present a uniform API)
|
||||
def access(self, *args, **kwargs):
|
||||
"Dummy method to mimic the logged-in API."
|
||||
"""Dummy method to mimic the logged-in API."""
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ from twisted.web.wsgi import WSGIResource
|
|||
from django.conf import settings
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
|
||||
from evennia.utils import logger
|
||||
|
||||
_UPSTREAM_IPS = settings.UPSTREAM_IPS
|
||||
_DEBUG = settings.DEBUG
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ class EvenniaReverseProxyResource(ReverseProxyResource):
|
|||
resource (EvenniaReverseProxyResource): A proxy resource.
|
||||
|
||||
"""
|
||||
request.notifyFinish().addErrback(lambda f: logger.log_trace("%s\nCaught errback in webserver.py:75." % f))
|
||||
return EvenniaReverseProxyResource(
|
||||
self.host, self.port, self.path + '/' + urlquote(path, safe=""),
|
||||
self.reactor)
|
||||
|
|
@ -98,6 +101,8 @@ class EvenniaReverseProxyResource(ReverseProxyResource):
|
|||
request.getAllHeaders(), request.content.read(), request)
|
||||
clientFactory.noisy = False
|
||||
self.reactor.connectTCP(self.host, self.port, clientFactory)
|
||||
# don't trigger traceback if connection is lost before request finish.
|
||||
request.notifyFinish().addErrback(lambda f: f.cancel())
|
||||
return NOT_DONE_YET
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue