From d5b3b59eb74406b7d0cd4eae88dd4ace7820011a Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 16 Apr 2016 18:46:29 +0200 Subject: [PATCH] Made webclient aware of the server dropping (both websocket and AJAX). The server currently reacts to the websocket client dropping but not to the AJAX one (the latter forms ghost players) --- evennia/server/portal/portal.py | 2 ++ evennia/server/portal/telnet.py | 4 +-- evennia/server/portal/telnet_oob.py | 20 ++++++--------- evennia/server/portal/webclient.py | 4 +-- evennia/server/portal/webclient_ajax.py | 7 +++--- .../static/webclient/css/webclient.css | 7 +----- .../webclient/static/webclient/js/evennia.js | 19 +++++++++++--- .../static/webclient/js/webclient_gui.js | 25 +++++++++++++++---- 8 files changed, 51 insertions(+), 37 deletions(-) diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 4f7fe2b048..02d501028b 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -168,6 +168,8 @@ class Portal(object): # we get here due to us calling reactor.stop below. No need # to do the shutdown procedure again. return + for session in self.sessions.itervalues(): + session.disconnect() self.set_restart_mode(restart) if os.name == 'nt' and os.path.exists(PORTAL_PIDFILE): # for Windows we need to remove pid files manually diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 7954b1006f..630910036f 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -206,7 +206,6 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def _write(self, data): "hook overloading the one used in plain telnet" - print "Activated GMCP" data = data.replace('\n', '\r\n').replace('\r\r\n', '\r\n') #data = data.replace('\n', '\r\n') super(TelnetProtocol, self)._write(mccp_compress(self, data)) @@ -246,8 +245,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): reason (str): Reason for disconnecting. """ - if reason: - self.data_out(text=[[reason], {}]) + self.data_out(connection_close=((reason or "",), {})) self.connectionLost(reason) def data_in(self, **kwargs): diff --git a/evennia/server/portal/telnet_oob.py b/evennia/server/portal/telnet_oob.py index 7c9ddd4ffe..69e236dca6 100644 --- a/evennia/server/portal/telnet_oob.py +++ b/evennia/server/portal/telnet_oob.py @@ -105,7 +105,6 @@ class TelnetOOB(object): """ # no msdp, check GMCP self.protocol.handshake_done() - print "No MSDP." def do_msdp(self, option): """ @@ -118,7 +117,6 @@ class TelnetOOB(object): self.MSDP = True self.protocol.protocol_flags['OOB'] = True self.protocol.handshake_done() - print "Activated MSDP" def no_gmcp(self, option): """ @@ -130,7 +128,6 @@ class TelnetOOB(object): """ self.protocol.handshake_done() - print "No GMCP." def do_gmcp(self, option): """ @@ -143,7 +140,6 @@ class TelnetOOB(object): self.GMCP = True self.protocol.protocol_flags['OOB'] = True self.protocol.handshake_done() - print "Activated GMCP" # encoders @@ -177,7 +173,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 msdp_args = '' if args: @@ -210,7 +206,7 @@ class TelnetOOB(object): msdp_string = msdp_args + msdp_kwargs - print "msdp_string:", msdp_string + #print "msdp_string:", msdp_string return msdp_string def encode_gmcp(self, cmdname, *args, **kwargs): @@ -246,7 +242,7 @@ class TelnetOOB(object): else: # only kwargs gmcp_string = "%s %s" % (cmdname, json.dumps(kwargs)) - print "gmcp string", gmcp_string + #print "gmcp string", gmcp_string return gmcp_string def decode_msdp(self, data): @@ -276,7 +272,7 @@ class TelnetOOB(object): if hasattr(data, "__iter__"): data = "".join(data) - print "decode_msdp in:", data + #print "decode_msdp in:", data tables = {} arrays = {} @@ -331,7 +327,7 @@ class TelnetOOB(object): for key, var in variables.iteritems(): cmds[key] = [[var], {}] - print "msdp data in:", cmds + #print "msdp data in:", cmds self.protocol.data_in(**cmds) @@ -358,7 +354,7 @@ class TelnetOOB(object): if hasattr(data, "__iter__"): data = "".join(data) - print "decode_gmcp in:", data + #print "decode_gmcp in:", data if data: try: cmdname, structure = data.split(None, 1) @@ -398,7 +394,7 @@ class TelnetOOB(object): if self.MSDP: msdp_cmdname = cmdname encoded_oob = self.encode_msdp(msdp_cmdname, *args, **kwargs) - print "sending MSDP:", encoded_oob + #print "sending MSDP:", encoded_oob self.protocol._write(IAC + SB + MSDP + encoded_oob + IAC + SE) if self.GMCP: @@ -408,5 +404,5 @@ class TelnetOOB(object): gmcp_cmdname = "Custom.Cmd" kwargs["cmdname"] = cmdname encoded_oob = self.encode_gmcp(gmcp_cmdname, *args, **kwargs) - print "sending GMCP:", encoded_oob + #print "sending GMCP:", encoded_oob self.protocol._write(IAC + SB + GMCP + encoded_oob + IAC + SE) diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index 3882766d12..d4eafde5f7 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -64,8 +64,7 @@ class WebSocketClient(Protocol, Session): reason (str): Motivation for the disconnection. """ - if reason: - self.data_out(text=[[reason],{}]) + self.data_out(connection_close=((reason or "",), {})) self.connectionLost(reason) def connectionLost(self, reason): @@ -123,7 +122,6 @@ class WebSocketClient(Protocol, Session): if "websocket_close" in kwargs: self.disconnect() return - print "websocket in:", kwargs self.sessionhandler.data_in(self, **kwargs) def data_out(self, **kwargs): diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index 9280ec30ee..a889e72a5c 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -26,7 +26,7 @@ from twisted.web import server, resource from django.utils.functional import Promise from django.utils.encoding import force_unicode from django.conf import settings -from evennia.utils import utils, logger +from evennia.utils import utils from evennia.utils.text2html import parse_html from evennia.server import session @@ -245,15 +245,14 @@ class WebClientSession(session.Session): This represents a session running in a webclient. """ - def disconnect(self, reason=None): + def disconnect(self, reason="Server disconnected."): """ Disconnect from server. Args: reason (str): Motivation for the disconnect. """ - if reason: - self.client.lineSend(self.suid, ["text", [reason], {}]) + self.client.lineSend(self.suid, ["connection_close", [reason], {}]) self.client.client_disconnect(self.suid) def data_out(self, **kwargs): diff --git a/evennia/web/webclient/static/webclient/css/webclient.css b/evennia/web/webclient/static/webclient/css/webclient.css index baa6493e7a..d0211b0d11 100644 --- a/evennia/web/webclient/static/webclient/css/webclient.css +++ b/evennia/web/webclient/static/webclient/css/webclient.css @@ -29,11 +29,6 @@ a:hover, a:active { color: #ccc } strong {font-weight:normal;} div {margin:0px;} -/* Base style for new messages in the main message area */ -/*.msg { - white-space: pre-wrap; } - padding: .5em .9em;} */ - /*border-bottom: 1px dotted #222 } /*optional line between messages */ /* Utility messages (green) */ .sys { color: #0f0 } @@ -45,7 +40,7 @@ div {margin:0px;} .out { color: #aaa } /* Error messages (red) */ -.err { color: #f00 } +.err { color: #f00; } /* Prompt base (white) */ .prompt {color: #fff } diff --git a/evennia/web/webclient/static/webclient/js/evennia.js b/evennia/web/webclient/static/webclient/js/evennia.js index 19a68de4c9..114d81b8c9 100644 --- a/evennia/web/webclient/static/webclient/js/evennia.js +++ b/evennia/web/webclient/static/webclient/js/evennia.js @@ -195,20 +195,31 @@ An "emitter" object must have a function // var WebsocketConnection = function () { log("Trying websocket ..."); + wsurl = "ws://blah"; + var open = false; var websocket = new WebSocket(wsurl); // Handle Websocket open event websocket.onopen = function (event) { + open = true; Evennia.emit('connection_open', ["websocket"], event); }; // Handle Websocket close event websocket.onclose = function (event) { - Evennia.emit('connection_close', ["websocket"], event); + if (open) { + // only emit if websocket was ever open at all + Evennia.emit('connection_close', ["websocket"], event); + } + open = false; }; // Handle websocket errors websocket.onerror = function (event) { - Evennia.emit('connection_error', ["websocket"], event); if (websocket.readyState === websocket.CLOSED) { log("Websocket failed. Falling back to Ajax..."); + if (open) { + // only emit if websocket was ever open at all. + Evennia.emit('connection_error', ["websocket"], event); + } + open = false; Evennia.connection = AjaxCometConnection(); } }; @@ -232,6 +243,7 @@ An "emitter" object must have a function // tied to when the client window is closed). This // Makes use of a websocket-protocol specific instruction. websocket.send(JSON.stringify(["websocket_close", [], {}])); + open = false; } return websocket; }; @@ -264,7 +276,6 @@ An "emitter" object must have a function // Send Client -> Evennia. Called by Evennia.msg var msg = function(data) { - log("AJAX.msg:", data); $.ajax({type: "POST", url: "/webclientdata", async: true, cache: false, timeout: 30000, dataType: "json", @@ -287,8 +298,8 @@ An "emitter" object must have a function dataType: "json", data: {mode: 'receive', 'suid': client_hash}, success: function(data) { + log("ajax data received:", data); Evennia.emit(data[0], data[1], data[2]); - log("AJAX/COMET: Evennia->client", data); poll(); // immiately start a new request }, error: function(req, stat, err) { diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index a06c1ca682..c49581ecb4 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -179,9 +179,10 @@ function doWindowResize() { // Handle text coming from the server function onText(args, kwargs) { // append message to previous ones, then scroll so latest is at - // the bottom. + // the bottom. Send 'cls' kwarg to modify the output class. var mwin = $("#messagewindow"); - mwin.append("
" + args[0] + "
"); + var cls = kwargs == null ? 'out' : kwargs['cls']; + mwin.append("
" + args[0] + "
"); mwin.animate({ scrollTop: document.getElementById("messagewindow").scrollHeight }, 0); @@ -191,7 +192,7 @@ function onText(args, kwargs) { function onPrompt(args, kwargs) { // show prompt $('#prompt') - .addClass("msg out") + .addClass("out") .html(args[0]); doWindowResize(); } @@ -199,9 +200,22 @@ function onPrompt(args, kwargs) { // Silences events we don't do anything with. function onSilence(cmdname, args, kwargs) {} +// Handle the server connection closing +function onConnectionClose(conn_name, evt) { + onText(["The connection was closed or lost."], {'cls': 'err'}); +} + +// Handle a connection error +function onConnectionError(conn_name, evt) { + if (conn_name[0].lastIndexOf("AJAX/COMET", 0) === 0) { + // only display anything if the error is in AJAX/COMET + onText(["The connection was closed or lost."], {'cls': 'err'}); + } +} + // Handle unrecognized commands from server function onDefault(cmdname, args, kwargs) { - mwin = $("#messagewindow"); + var mwin = $("#messagewindow"); mwin.append( "
" + "Error or Unhandled event:
" @@ -240,7 +254,8 @@ $(document).ready(function() { Evennia.emitter.on("default", onDefault); // silence currently unused events Evennia.emitter.on("connection_open", onSilence); - Evennia.emitter.on("connection_close", onSilence); + Evennia.emitter.on("connection_close", onConnectionClose); + Evennia.emitter.on("connection_error", onConnectionError); // Handle pressing the send button $("#inputsend").bind("click", doSendText);