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)

This commit is contained in:
Griatch 2016-04-16 18:46:29 +02:00
parent c46e115901
commit d5b3b59eb7
8 changed files with 51 additions and 37 deletions

View file

@ -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

View file

@ -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):

View file

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

View file

@ -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):

View file

@ -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):

View file

@ -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 }

View file

@ -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) {

View file

@ -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("<div class='msg out'>" + args[0] + "</div>");
var cls = kwargs == null ? 'out' : kwargs['cls'];
mwin.append("<div class='" + cls + "'>" + args[0] + "</div>");
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(
"<div class='msg err'>"
+ "Error or Unhandled event:<br>"
@ -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);