From 17dfcd4ed5e6e5186dd3fcc722e5cae7fbf41246 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 1 Nov 2020 16:12:56 +0100 Subject: [PATCH] Better report of tracebacks across AMP bridge, sort of related to #2240 --- evennia/server/portal/amp.py | 51 +++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/evennia/server/portal/amp.py b/evennia/server/portal/amp.py index 505ea5e3e0..6065a4fdfa 100644 --- a/evennia/server/portal/amp.py +++ b/evennia/server/portal/amp.py @@ -46,6 +46,14 @@ NULNUL = b"\x00\x00" AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed) +# amp internal +ASK = b'_ask' +ANSWER = b'_answer' +ERROR = b'_error' +ERROR_CODE = b'_error_code' +ERROR_DESCRIPTION = b'_error_description' +UNKNOWN_ERROR_CODE = b'UNKNOWN' + # buffers _SENDBATCH = defaultdict(list) _MSGBUFFER = defaultdict(list) @@ -301,6 +309,47 @@ class AMPMultiConnectionProtocol(amp.AMP): # later twisted amp has its own __init__ super(AMPMultiConnectionProtocol, self).__init__(*args, **kwargs) + def _commandReceived(self, box): + """ + This overrides the default Twisted AMP error handling which is not + passing enough of the traceback through to the other side. Instead we + add a specific log of the problem on the erroring side. + + """ + def formatAnswer(answerBox): + answerBox[ANSWER] = box[ASK] + return answerBox + + def formatError(error): + if error.check(amp.RemoteAmpError): + code = error.value.errorCode + desc = error.value.description + + # Evennia extra logging + desc += " (error logged on other side)" + _get_logger().log_err(f"AMP caught exception ({desc}):\n{error.value}") + + if isinstance(desc, str): + desc = desc.encode("utf-8", "replace") + if error.value.fatal: + errorBox = amp.QuitBox() + else: + errorBox = amp.AmpBox() + else: + errorBox = amp.QuitBox() + _get_logger().log_err(error) # server-side logging if unhandled error + code = UNKNOWN_ERROR_CODE + desc = b"Unknown Error" + errorBox[ERROR] = box[ASK] + errorBox[ERROR_DESCRIPTION] = desc + errorBox[ERROR_CODE] = code + return errorBox + deferred = self.dispatchCommand(box) + if ASK in box: + deferred.addCallbacks(formatAnswer, formatError) + deferred.addCallback(self._safeEmit) + deferred.addErrback(self.unhandledError) + def dataReceived(self, data): """ Handle non-AMP messages, such as HTTP communication. @@ -385,7 +434,7 @@ class AMPMultiConnectionProtocol(amp.AMP): """ e.trap(Exception) _get_logger().log_err( - "AMP Error for {info}: {trcbck} {err}".format( + "AMP Error from {info}: {trcbck} {err}".format( info=info, trcbck=e.getTraceback(), err=e.getErrorMessage() ) )