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);