diff --git a/evennia/server/portal/amp.py b/evennia/server/portal/amp.py
index 4ff4732708..71a1bcba91 100644
--- a/evennia/server/portal/amp.py
+++ b/evennia/server/portal/amp.py
@@ -44,9 +44,10 @@ SSHUTD = chr(17) # server shutdown
PSTATUS = chr(18) # ping server or portal status
SRESET = chr(19) # server shutdown in reset mode
+NUL = b'\0'
+NULNUL = '\0\0'
+
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
# buffers
_SENDBATCH = defaultdict(list)
@@ -61,11 +62,15 @@ _HTTP_WARNING = """
HTTP/1.1 200 OK
Content-Type: text/html
-
-This is Evennia's interal AMP port. It handles communication
-between Evennia's different processes.This port should NOT be
-publicly visible.
-""".strip()
+
+
+ This is Evennia's internal AMP port. It handles communication
+ between Evennia's different processes.
+
+
This port should NOT be publicly visible.
+
+
+""".strip()
# Helper functions for pickling.
@@ -107,43 +112,45 @@ class Compressed(amp.String):
def fromBox(self, name, strings, objects, proto):
"""
- Converts from box representation to python. We
- group very long data into batches.
+ Converts from box string representation to python. We read back too-long batched data and
+ put it back together here.
+
"""
value = StringIO()
- value.write(strings.get(name))
+ value.write(self.fromStringProto(strings.get(name), proto))
for counter in count(2):
# count from 2 upwards
chunk = strings.get("%s.%d" % (name, counter))
if chunk is None:
break
- value.write(chunk)
+ value.write(self.fromStringProto(chunk, proto))
objects[name] = value.getvalue()
def toBox(self, name, strings, objects, proto):
"""
- Convert from data to box. We handled too-long
- batched data and put it together here.
+ Convert from python object to string box representation.
+ we break up too-long data snippets into multiple batches here.
+
"""
value = StringIO(objects[name])
- strings[name] = value.read(AMP_MAXLEN)
+ strings[name] = self.toStringProto(value.read(AMP_MAXLEN), proto)
for counter in count(2):
chunk = value.read(AMP_MAXLEN)
if not chunk:
break
- strings["%s.%d" % (name, counter)] = chunk
+ strings["%s.%d" % (name, counter)] = self.toStringProto(chunk, proto)
def toString(self, inObject):
"""
- Convert to send on the wire, with compression.
+ Convert to send as a string on the wire, with compression.
"""
- return zlib.compress(inObject, 9)
+ return zlib.compress(super(Compressed, self).toString(inObject), 9)
def fromString(self, inString):
"""
- Convert (decompress) from the wire to Python.
+ Convert (decompress) from the string-representation on the wire to Python.
"""
- return zlib.decompress(inString)
+ return super(Compressed, self).fromString(zlib.decompress(inString))
class MsgLauncher2Portal(amp.Command):
@@ -261,16 +268,29 @@ class AMPMultiConnectionProtocol(amp.AMP):
self.send_reset_time = time.time()
self.send_mode = True
self.send_task = None
+ self.multibatches = 0
def dataReceived(self, data):
"""
Handle non-AMP messages, such as HTTP communication.
"""
- if data[0] != b'\0':
+ if data[0] == NUL:
+ # an AMP communication
+ if data[-2:] != NULNUL:
+ # an incomplete AMP box means more batches are forthcoming.
+ self.multibatches += 1
+ super(AMPMultiConnectionProtocol, self).dataReceived(data)
+ elif self.multibatches:
+ # invalid AMP, but we have a pending multi-batch that is not yet complete
+ if data[-2:] == NULNUL:
+ # end of existing multibatch
+ self.multibatches = max(0, self.multibatches - 1)
+ super(AMPMultiConnectionProtocol, self).dataReceived(data)
+ else:
+ # not an AMP communication, return warning
self.transport.write(_HTTP_WARNING)
self.transport.loseConnection()
- else:
- super(AMPMultiConnectionProtocol, self).dataReceived(data)
+ print("HTML received: %s" % data)
def makeConnection(self, transport):
"""
diff --git a/evennia/server/portal/amp_server.py b/evennia/server/portal/amp_server.py
index c550a648c3..38e39fb464 100644
--- a/evennia/server/portal/amp_server.py
+++ b/evennia/server/portal/amp_server.py
@@ -356,10 +356,13 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
packed_data (str): Pickled data (sessid, kwargs) coming over the wire.
"""
- sessid, kwargs = self.data_in(packed_data)
- session = self.factory.portal.sessions.get(sessid, None)
- if session:
- self.factory.portal.sessions.data_out(session, **kwargs)
+ try:
+ sessid, kwargs = self.data_in(packed_data)
+ session = self.factory.portal.sessions.get(sessid, None)
+ if session:
+ self.factory.portal.sessions.data_out(session, **kwargs)
+ except Exception:
+ logger.log_trace("packed_data len {}".format(len(packed_data)))
return {}
@amp.AdminServer2Portal.responder